1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Merge master into dynamic-import.

This commit is contained in:
Arunoda Susiripala 2017-04-18 21:42:21 +05:30
commit 90ea471aa7
27 changed files with 294 additions and 183 deletions

View file

@ -1,6 +1,6 @@
{
"presets": [
"latest",
"env",
"react"
],
"plugins": [

View file

@ -1,9 +1,10 @@
#!/usr/bin/env node
import { join } from 'path'
import { join, resolve } from 'path'
import { spawn } from 'cross-spawn'
import { watchFile } from 'fs'
import pkg from '../../package.json'
import getConfig from '../server/config'
if (pkg.peerDependencies) {
Object.keys(pkg.peerDependencies).forEach(dependency => {
@ -78,9 +79,10 @@ const startProcess = () => {
}
let proc = startProcess()
const { pagesDirectory = resolve(process.cwd(), 'pages') } = getConfig(process.cwd())
if (cmd === 'dev') {
watchFile(join(process.cwd(), 'next.config.js'), (cur, prev) => {
watchFile(`${resolve(pagesDirectory, '..')}/next.config.js`, (cur, prev) => {
if (cur.size > 0 || prev.size > 0) {
console.log('\n> Found a change in next.config.js, restarting the server...')
// Don't listen to 'close' now since otherwise parent gets killed by listener

View file

@ -24,12 +24,13 @@ const {
pathname,
query,
buildId,
chunks
chunks,
assetPrefix
},
location
} = window
const pageLoader = new PageLoader(buildId)
const pageLoader = new PageLoader(buildId, assetPrefix)
window.__NEXT_LOADED_PAGES__.forEach(({ route, fn }) => {
pageLoader.registerPage(route, fn)
})

View file

@ -1,4 +1,4 @@
import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?overlay=false&reload=true'
import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?overlay=false&reload=true&path=/_next/webpack-hmr'
import Router from '../lib/router'
export default () => {

View file

@ -12,14 +12,16 @@ const match = route('/blog/:id')
app.prepare()
.then(() => {
createServer((req, res) => {
const { pathname } = parse(req.url)
const { pathname, query } = parse(req.url, true)
const params = match(pathname)
if (params === false) {
handle(req, res)
return
}
app.render(req, res, '/blog', params)
// assigning `query` into the params means that we still
// get the query string passed to our application
// i.e. /blog/foo?show-comments=true
app.render(req, res, '/blog', Object.assign(params, query))
})
.listen(3000, (err) => {
if (err) throw err

View file

@ -37,7 +37,7 @@ Another babel plugin [module-resolver](https://github.com/tleunen/babel-plugin-m
The `sass-loader` is configured with `includePaths: ['styles', 'node_modules']` so that your scss can `@import` from those places, again without relative paths, for maximum convenience and ability to use npm-published libraries. Furthermore, `glob` paths are also supported, so one could for example add `'node_modules/@material/*'` to the `includePaths`, which would make [material-components-web](https://github.com/material-components/material-components-web) (if you'd like) even easier to work with.
Furthermore, PostCSS is used to [pre-process](https://blog.madewithenvy.com/webpack-2-postcss-cssnext-fdcd2fd7d0bd#.r6t2d0smy) both `css` and `scss` stylesheets, the latter after Sass pre-processing. This is to illustrate `@import 'normalize.css';` from `node_modules` thanks to `postcss-easy-import`. [Autoprefixer](https://github.com/postcss/autoprefixer) is also added as a "best practice". Consider [cssnext](http://cssnext.io) instead, which includes `autoprefixer` as well as many other CSS spec features.
Furthermore, PostCSS is used to [pre-process](https://medium.com/@ddprrt/deconfusing-pre-and-post-processing-d68e3bd078a3) both `css` and `scss` stylesheets, the latter after Sass pre-processing. This is to illustrate `@import 'normalize.css';` from `node_modules` thanks to `postcss-easy-import`. [Autoprefixer](https://github.com/postcss/autoprefixer) is also added as a "best practice". Consider [cssnext](http://cssnext.io) instead, which includes `autoprefixer` as well as many other CSS spec features.
This project shows how you can set it up. Have a look at:
- .babelrc

View file

@ -8,6 +8,7 @@
"express": "^4.15.2",
"next": "^2.0.0",
"next-url-prettifier": "^1.0.2",
"prop-types": "^15.5.6",
"react": "^15.4.2",
"react-dom": "^15.4.2"
}

View file

@ -1,4 +1,5 @@
import React from 'react'
import PropTypes from 'prop-types'
import {Link} from 'next-url-prettifier'
import {Router} from '../routes'
@ -29,6 +30,6 @@ export default class GreetingPage extends React.Component {
}
GreetingPage.propTypes = {
lang: React.PropTypes.string,
name: React.PropTypes.string
lang: PropTypes.string,
name: PropTypes.string
}

View file

@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { AppContainer } from 'react-hot-loader'
import shallowEquals from './shallow-equals'
import { warn } from './utils'

View file

@ -1,9 +1,10 @@
import React from 'react'
import PropTypes from 'prop-types'
import sideEffect from './side-effect'
class Head extends React.Component {
static contextTypes = {
headManager: React.PropTypes.object
headManager: PropTypes.object
}
render () {

View file

@ -1,5 +1,6 @@
import { resolve, format, parse } from 'url'
import React, { Component, Children, PropTypes } from 'react'
import React, { Component, Children } from 'react'
import PropTypes from 'prop-types'
import Router from './router'
import { warn, execOnce, getLocationOrigin } from './utils'

View file

@ -4,8 +4,10 @@ import mitt from 'mitt'
const webpackModule = module
export default class PageLoader {
constructor (buildId) {
constructor (buildId, assetPrefix) {
this.buildId = buildId
this.assetPrefix = assetPrefix
this.pageCache = {}
this.pageLoadedHandlers = {}
this.pageRegisterEvents = mitt()
@ -59,7 +61,7 @@ export default class PageLoader {
route = this.normalizeRoute(route)
const script = document.createElement('script')
const url = `/_next/${encodeURIComponent(this.buildId)}/page${route}`
const url = `${this.assetPrefix}/_next/${encodeURIComponent(this.buildId)}/page${route}`
script.src = url
script.type = 'text/javascript'
script.onerror = () => {

View file

@ -81,8 +81,8 @@ export default class Router {
if (route !== this.route) return
const { pathname, query } = this
const url = window.location.href
const { pathname, query } = parse(url, true)
this.events.emit('routeChangeStart', url)
const routeInfo = await this.getRouteInfo(route, pathname, query, url)

View file

@ -1,13 +1,10 @@
{
"name": "next",
"version": "2.0.1",
"version": "2.1.1",
"description": "Minimalistic framework for server-rendered React applications",
"main": "./dist/server/next.js",
"license": "MIT",
"repository": "zeit/next.js",
"publishConfig": {
"tag": "beta"
},
"files": [
"dist",
"babel.js",
@ -57,17 +54,19 @@
"babel-plugin-transform-es2015-modules-commonjs": "6.24.0",
"babel-plugin-transform-object-rest-spread": "6.22.0",
"babel-plugin-transform-react-jsx-source": "6.22.0",
"babel-plugin-transform-react-remove-prop-types": "0.3.2",
"babel-plugin-transform-react-remove-prop-types": "0.4.0",
"babel-plugin-transform-runtime": "6.22.0",
"babel-preset-latest": "6.24.0",
"babel-preset-env": "1.3.3",
"babel-preset-react": "6.23.0",
"babel-runtime": "6.23.0",
"babel-template": "6.24.1",
"case-sensitive-paths-webpack-plugin": "2.0.0",
"cross-spawn": "5.1.0",
"del": "2.2.2",
"etag": "1.8.0",
"fresh": "0.5.0",
"friendly-errors-webpack-plugin": "1.5.0",
"glob": "^7.1.1",
"glob": "7.1.1",
"glob-promise": "3.1.0",
"htmlescape": "1.1.1",
"http-status": "1.0.1",
@ -82,6 +81,7 @@
"mz": "2.6.0",
"path-match": "1.2.4",
"pkg-up": "1.0.0",
"prop-types": "15.5.7",
"react-hot-loader": "3.0.0-beta.6",
"send": "0.15.1",
"source-map-support": "0.4.14",
@ -97,14 +97,14 @@
"write-file-webpack-plugin": "4.0.0"
},
"devDependencies": {
"babel-eslint": "7.2.0",
"babel-eslint": "7.2.2",
"babel-jest": "18.0.0",
"babel-plugin-istanbul": "4.1.1",
"babel-plugin-transform-remove-strict-mode": "0.0.2",
"babel-preset-es2015": "6.24.0",
"benchmark": "2.1.4",
"cheerio": "0.22.0",
"chromedriver": "2.28.0",
"chromedriver": "2.29.0",
"coveralls": "2.13.0",
"cross-env": "4.0.0",
"fly": "2.0.5",
@ -118,8 +118,8 @@
"node-fetch": "1.6.3",
"node-notifier": "5.1.2",
"nyc": "10.2.0",
"react": "15.4.2",
"react-dom": "15.4.2",
"react": "15.5.3",
"react-dom": "15.5.3",
"standard": "9.0.2",
"wd": "1.2.0"
},

View file

@ -11,6 +11,7 @@ Next.js is a minimalistic framework for server-rendered React applications.
<!-- https://github.com/thlorenz/doctoc -->
- [How to use](#how-to-use)
- [Getting Started](#getting-started)
- [Setup](#setup)
- [Automatic code splitting](#automatic-code-splitting)
- [CSS](#css)
@ -33,9 +34,9 @@ Next.js is a minimalistic framework for server-rendered React applications.
- [Custom configuration](#custom-configuration)
- [Customizing webpack config](#customizing-webpack-config)
- [Customizing babel config](#customizing-babel-config)
- [CDN support with Asset Prefix](#cdn-support-with-asset-prefix)
- [Production deployment](#production-deployment)
- [FAQ](#faq)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
- [Authors](#authors)
@ -43,6 +44,10 @@ Next.js is a minimalistic framework for server-rendered React applications.
## How to use
### Getting Started
A step by step interactive guide of next features is available at [learnnextjs.com](https://learnnextjs.com/)
### Setup
Install it:
@ -298,7 +303,7 @@ The component `<Link>` can also receive an URL object and it will automatically
// pages/index.js
import Link from 'next/link'
export default () => (
<div>Click <Link href={{ pathname: 'about', query: { name: 'Zeit' }}}<a>here</a></Link> to read more</div>
<div>Click <Link href={{ pathname: 'about', query: { name: 'Zeit' }}}><a>here</a></Link> to read more</div>
)
```
@ -700,6 +705,20 @@ Here's an example `.babelrc` file:
}
```
### CDN support with Asset Prefix
To set up a CDN, you can set up the `assetPrefix` setting and configure your CDN's origin to resolve to the domain that Next.js is hosted on.
```js
const isProd = process.NODE_ENV === 'production'
module.exports = {
// You may only need to add assetPrefix in the production.
assetPrefix: isProd ? 'https://cdn.mydomain.com' : ''
}
```
Note: Next.js will automatically use that prefix the scripts it loads, but this has no effect whatsoever on `/static`. If you want to serve those assets over the CDN, you'll have to introduce the prefix yourself. One way of introducing a prefix that works inside your components and varies by environment is documented [in this example](https://github.com/zeit/next.js/tree/master/examples/with-universal-configuration).
## Production deployment
To deploy, instead of running `next`, you want to build for production usage ahead of time. Therefore, building and starting are separate commands:
@ -840,10 +859,6 @@ As we were researching options for server-rendering React that didnt involve
</details>
## Roadmap
Our Roadmap towards 2.0.0 [is public](https://github.com/zeit/next.js/wiki/Roadmap#nextjs-200).
## Contributing
Please see our [contributing.md](./contributing.md)

View file

@ -13,8 +13,8 @@ const plugins = envPlugins[process.env.NODE_ENV] || []
module.exports = {
presets: [
[require.resolve('babel-preset-latest'), {
'es2015': { modules: false }
[require.resolve('babel-preset-env'), {
modules: false
}],
require.resolve('babel-preset-react')
],

View file

@ -1,6 +1,5 @@
import { tmpdir } from 'os'
import { join } from 'path'
import getConfig from '../config'
import fs from 'mz/fs'
import uuid from 'uuid'
import del from 'del'
@ -14,10 +13,8 @@ export default async function build (dir) {
try {
await runCompiler(compiler)
// Pass in both the buildDir and the dir to retrieve config
await writeBuildStats(buildDir, dir)
await writeBuildId(buildDir, dir)
await writeBuildStats(buildDir)
await writeBuildId(buildDir)
} catch (err) {
console.error(`> Failed to build on ${buildDir}`)
throw err
@ -48,24 +45,22 @@ function runCompiler (compiler) {
})
}
async function writeBuildStats (buildDir, dir) {
const dist = getConfig(dir).distDir
async function writeBuildStats (dir) {
// Here we can't use hashes in webpack chunks.
// That's because the "app.js" is not tied to a chunk.
// It's created by merging a few assets. (commons.js and main.js)
// So, we need to generate the hash ourself.
const assetHashMap = {
'app.js': {
hash: await md5File(join(buildDir, dist, 'app.js'))
hash: await md5File(join(dir, '.next', 'app.js'))
}
}
const buildStatsPath = join(buildDir, dist, 'build-stats.json')
const buildStatsPath = join(dir, '.next', 'build-stats.json')
await fs.writeFile(buildStatsPath, JSON.stringify(assetHashMap), 'utf8')
}
async function writeBuildId (buildDir, dir) {
const dist = getConfig(dir).distDir
const buildIdPath = join(buildDir, dist, 'BUILD_ID')
async function writeBuildId (dir) {
const buildIdPath = join(dir, '.next', 'BUILD_ID')
const buildId = uuid.v4()
await fs.writeFile(buildIdPath, buildId, 'utf8')
}

View file

@ -4,10 +4,9 @@ import getConfig from '../config'
export default async function replaceCurrentBuild (dir, buildDir) {
const dist = getConfig(dir).distDir
const buildDist = getConfig(buildDir).distDir
const _dir = join(dir, dist)
const _buildDir = join(buildDir, dist)
const oldDir = join(buildDir, `${buildDist}.old`)
const _buildDir = join(buildDir, '.next')
const oldDir = join(buildDir, '.next.old')
try {
await move(_dir, oldDir)

View file

@ -37,7 +37,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
const mainJS = dev
? require.resolve('../../client/next-dev') : require.resolve('../../client/next')
let minChunks
let totalPages
const entry = async () => {
const entries = {
@ -69,8 +69,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
}
}
// calculate minChunks of CommonsChunkPlugin for later use
minChunks = Math.max(2, pages.filter((p) => p !== documentPage).length)
totalPages = pages.filter((p) => p !== documentPage).length
return entries
}
@ -102,9 +101,8 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
return module.context && module.context.indexOf('node_modules') >= 0
}
// NOTE: it depends on the fact that the entry funtion is always called
// before applying CommonsChunkPlugin
return count >= minChunks
// Move modules used in at-least 1/2 of the total pages into commons.
return count >= totalPages * 0.5
}
}),
// This chunk contains all the webpack related code. So, all the changes
@ -268,10 +266,10 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
context: dir,
entry,
output: {
path: join(buildDir || dir, config.distDir),
path: buildDir ? join(buildDir, '.next') : join(dir, config.distDir),
filename: '[name]',
libraryTarget: 'commonjs2',
publicPath: '/_webpack/',
publicPath: '/_next/webpack/',
strictModuleExceptionHandling: true,
devtoolModuleFilenameTemplate ({ resourcePath }) {
const hash = createHash('sha1')

View file

@ -6,7 +6,8 @@ const cache = new Map()
const defaultConfig = {
webpack: null,
poweredByHeader: true,
distDir: '.next'
distDir: '.next',
assetPrefix: ''
}
export default function getConfig (dir) {

View file

@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import htmlescape from 'htmlescape'
import flush from 'styled-jsx/server'
@ -35,14 +36,14 @@ export class Head extends Component {
getChunkPreloadLink (filename) {
const { __NEXT_DATA__ } = this.context._documentProps
let { buildStats } = __NEXT_DATA__
let { buildStats, assetPrefix } = __NEXT_DATA__
const hash = buildStats ? buildStats[filename].hash : '-'
return (
<link
key={filename}
rel='preload'
href={`/_next/${hash}/${filename}`}
href={`${assetPrefix}/_next/${hash}/${filename}`}
as='script'
/>
)
@ -65,12 +66,13 @@ export class Head extends Component {
}
getPreloadDynamicChunks () {
const { chunks } = this.context._documentProps
const { chunks, __NEXT_DATA__ } = this.context._documentProps
let { assetPrefix } = __NEXT_DATA__
return chunks.map((chunk) => (
<link
key={chunk}
rel='preload'
href={`/_webpack/chunks/${chunk}`}
href={`${assetPrefix}/_next/webpack/chunks/${chunk}`}
as='script'
/>
))
@ -78,11 +80,11 @@ export class Head extends Component {
render () {
const { head, styles, __NEXT_DATA__ } = this.context._documentProps
const { pathname, buildId } = __NEXT_DATA__
const { pathname, buildId, assetPrefix } = __NEXT_DATA__
return <head>
<link rel='preload' href={`/_next/${buildId}/page${pathname}`} as='script' />
<link rel='preload' href={`/_next/${buildId}/page/_error`} as='script' />
<link rel='preload' href={`${assetPrefix}/_next/${buildId}/page${pathname}`} as='script' />
<link rel='preload' href={`${assetPrefix}/_next/${buildId}/page/_error`} as='script' />
{this.getPreloadDynamicChunks()}
{this.getPreloadMainLinks()}
{(head || []).map((h, i) => React.cloneElement(h, { key: i }))}
@ -115,13 +117,13 @@ export class NextScript extends Component {
getChunkScript (filename, additionalProps = {}) {
const { __NEXT_DATA__ } = this.context._documentProps
let { buildStats } = __NEXT_DATA__
let { buildStats, assetPrefix } = __NEXT_DATA__
const hash = buildStats ? buildStats[filename].hash : '-'
return (
<script
type='text/javascript'
src={`/_next/${hash}/${filename}`}
src={`${assetPrefix}/_next/${hash}/${filename}`}
{...additionalProps}
/>
)
@ -145,7 +147,8 @@ export class NextScript extends Component {
}
getDynamicChunks () {
const { chunks } = this.context._documentProps
const { chunks, __NEXT_DATA__ } = this.context._documentProps
let { assetPrefix } = __NEXT_DATA__
return (
<div>
{chunks.map((chunk) => (
@ -153,7 +156,7 @@ export class NextScript extends Component {
async
key={chunk}
type='text/javascript'
src={`/_webpack/chunks/${chunk}`}
src={`${assetPrefix}/_next/webpack/chunks/${chunk}`}
/>
))}
</div>
@ -162,7 +165,7 @@ export class NextScript extends Component {
render () {
const { staticMarkup, __NEXT_DATA__, chunks } = this.context._documentProps
const { pathname, buildId } = __NEXT_DATA__
const { pathname, buildId, assetPrefix } = __NEXT_DATA__
__NEXT_DATA__.chunks = chunks
@ -183,8 +186,8 @@ export class NextScript extends Component {
}
`
}} />}
<script async type='text/javascript' src={`/_next/${buildId}/page${pathname}`} />
<script async type='text/javascript' src={`/_next/${buildId}/page/_error`} />
<script async type='text/javascript' src={`${assetPrefix}/_next/${buildId}/page${pathname}`} />
<script async type='text/javascript' src={`${assetPrefix}/_next/${buildId}/page/_error`} />
{staticMarkup ? null : this.getDynamicChunks()}
{staticMarkup ? null : this.getScripts()}
</div>

View file

@ -139,7 +139,7 @@ export default class HotReloader {
} : {}
this.webpackDevMiddleware = webpackDevMiddleware(compiler, {
publicPath: '/_webpack/',
publicPath: '/_next/webpack/',
noInfo: true,
quiet: true,
clientLogLevel: 'warning',
@ -147,7 +147,10 @@ export default class HotReloader {
...windowsSettings
})
this.webpackHotMiddleware = webpackHotMiddleware(compiler, { log: false })
this.webpackHotMiddleware = webpackHotMiddleware(compiler, {
path: '/_next/webpack-hmr',
log: false
})
this.onDemandEntries = onDemandEntryHandler(this.webpackDevMiddleware, compiler, {
dir: this.dir,
dev: true,

View file

@ -18,6 +18,11 @@ import getConfig from './config'
// We need to go up one more level since we are in the `dist` directory
import pkg from '../../package'
const internalPrefixes = [
/^\/_next\//,
/^\/static\//
]
export default class Server {
constructor ({ dir = '.', dev = false, staticMarkup = false, quiet = false } = {}) {
this.dir = resolve(dir)
@ -36,31 +41,34 @@ export default class Server {
dir: this.dir,
hotReloader: this.hotReloader,
buildStats: this.buildStats,
buildId: this.buildId
buildId: this.buildId,
assetPrefix: this.config.assetPrefix.replace(/\/$/, '')
}
this.defineRoutes()
}
getRequestHandler () {
return (req, res, parsedUrl) => {
// Parse url if parsedUrl not provided
if (!parsedUrl) {
parsedUrl = parseUrl(req.url, true)
}
// Parse the querystring ourselves if the user doesn't handle querystring parsing
if (typeof parsedUrl.query === 'string') {
parsedUrl.query = parseQs(parsedUrl.query)
}
return this.run(req, res, parsedUrl)
.catch((err) => {
if (!this.quiet) console.error(err)
res.statusCode = 500
res.end(STATUS_CODES[500])
})
handleRequest (req, res, parsedUrl) {
// Parse url if parsedUrl not provided
if (!parsedUrl) {
parsedUrl = parseUrl(req.url, true)
}
// Parse the querystring ourselves if the user doesn't handle querystring parsing
if (typeof parsedUrl.query === 'string') {
parsedUrl.query = parseQs(parsedUrl.query)
}
return this.run(req, res, parsedUrl)
.catch((err) => {
if (!this.quiet) console.error(err)
res.statusCode = 500
res.end(STATUS_CODES[500])
})
}
getRequestHandler () {
return this.handleRequest.bind(this)
}
async prepare () {
@ -92,7 +100,7 @@ export default class Server {
},
// This is to support, webpack dynamic imports in production.
'/_webpack/chunks/:name': async (req, res, params) => {
'/_next/webpack/chunks/:name': async (req, res, params) => {
res.setHeader('Cache-Control', 'max-age=365000000, immutable')
const p = join(this.dir, '.next', 'chunks', params.name)
await this.serveStatic(req, res, p)
@ -215,12 +223,16 @@ export default class Server {
}
}
async render (req, res, pathname, query) {
async render (req, res, pathname, query, parsedUrl) {
if (this.isInternalUrl(req)) {
return this.handleRequest(req, res, parsedUrl)
}
if (this.config.poweredByHeader) {
res.setHeader('X-Powered-By', `Next.js ${pkg.version}`)
}
const html = await this.renderToHTML(req, res, pathname, query)
return sendHTML(res, html, req.method)
return sendHTML(req, res, html, req.method)
}
async renderToHTML (req, res, pathname, query) {
@ -248,7 +260,7 @@ export default class Server {
async renderError (err, req, res, pathname, query) {
const html = await this.renderErrorToHTML(err, req, res, pathname, query)
return sendHTML(res, html, req.method)
return sendHTML(req, res, html, req.method)
}
async renderErrorToHTML (err, req, res, pathname, query) {
@ -291,6 +303,16 @@ export default class Server {
}
}
isInternalUrl (req) {
for (const prefix of internalPrefixes) {
if (prefix.test(req.url)) {
return true
}
}
return false
}
readBuildId () {
const buildIdPath = join(this.dir, this.dist, 'BUILD_ID')
const buildId = fs.readFileSync(buildIdPath, 'utf8')

View file

@ -2,6 +2,8 @@ import { join } from 'path'
import { createElement } from 'react'
import { renderToString, renderToStaticMarkup } from 'react-dom/server'
import send from 'send'
import generateETag from 'etag'
import fresh from 'fresh'
import requireModule from './require'
import getConfig from './config'
import resolvePath from './resolve'
@ -14,7 +16,7 @@ import { flushChunks } from '../lib/dynamic'
export async function render (req, res, pathname, query, opts) {
const html = await renderToHTML(req, res, pathname, opts)
sendHTML(res, html, req.method)
sendHTML(req, res, html, req.method)
}
export function renderToHTML (req, res, pathname, query, opts) {
@ -23,7 +25,7 @@ export function renderToHTML (req, res, pathname, query, opts) {
export async function renderError (err, req, res, pathname, query, opts) {
const html = await renderErrorToHTML(err, req, res, query, opts)
sendHTML(res, html, req.method)
sendHTML(req, res, html, req.method)
}
export function renderErrorToHTML (err, req, res, pathname, query, opts = {}) {
@ -36,6 +38,7 @@ async function doRender (req, res, pathname, query, {
buildId,
buildStats,
hotReloader,
assetPrefix,
dir = process.cwd(),
dev = false,
staticMarkup = false
@ -95,6 +98,7 @@ async function doRender (req, res, pathname, query, {
query,
buildId,
buildStats,
assetPrefix,
err: (err && dev) ? errorToJSON(err) : null
},
dev,
@ -148,9 +152,17 @@ export async function renderScriptError (req, res, page, error, customFields, op
`)
}
export function sendHTML (res, html, method) {
export function sendHTML (req, res, html, method) {
if (res.finished) return
const etag = generateETag(html)
if (fresh(req.headers, { etag })) {
res.statusCode = 304
res.end()
return
}
res.setHeader('ETag', etag)
res.setHeader('Content-Type', 'text/html')
res.setHeader('Content-Length', Buffer.byteLength(html))
res.end(method === 'HEAD' ? null : html)

View file

@ -1,4 +1,5 @@
/* global describe, test, expect */
import fetch from 'node-fetch'
export default function (context) {
describe('Misc', () => {
@ -12,5 +13,14 @@ export default function (context) {
const html = await context.app.renderToHTML({}, res, '/finish-response', {})
expect(html).toBeFalsy()
})
test('allow etag header support', async () => {
const url = `http://localhost:${context.appPort}/stateless`
const etag = (await fetch(url)).headers.get('ETag')
const headers = { 'If-None-Match': etag }
const res2 = await fetch(url, { headers })
expect(res2.status).toBe(304)
})
})
}

View file

@ -4,7 +4,7 @@ import { pkg } from 'next-test-utils'
export default function ({ app }) {
describe('X-Powered-By header', () => {
test('set it by default', async () => {
const req = { url: '/stateless' }
const req = { url: '/stateless', headers: {} }
const headers = {}
const res = {
setHeader (key, value) {
@ -18,7 +18,7 @@ export default function ({ app }) {
})
test('do not set it when poweredByHeader==false', async () => {
const req = { url: '/stateless' }
const req = { url: '/stateless', headers: {} }
const originalConfigValue = app.config.poweredByHeader
app.config.poweredByHeader = false
const res = {

195
yarn.lock
View file

@ -289,15 +289,14 @@ babel-core@6.24.0, babel-core@^6.0.0, babel-core@^6.24.0, babel-core@^6.3.0:
slash "^1.0.0"
source-map "^0.5.0"
babel-eslint@7.2.0:
version "7.2.0"
resolved "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.0.tgz#8941514b9dead06f0df71b29d5d5b193a92ee0ae"
babel-eslint@7.2.2:
version "7.2.2"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.2.tgz#0da2cbe6554fd0fb069f19674f2db2f9c59270ff"
dependencies:
babel-code-frame "^6.22.0"
babel-traverse "^6.23.1"
babel-types "^6.23.0"
babylon "^6.16.1"
lodash "^4.17.4"
babel-generator@6.24.0, babel-generator@^6.18.0, babel-generator@^6.24.0:
version "6.24.0"
@ -504,7 +503,7 @@ babel-plugin-syntax-class-properties@^6.8.0:
version "6.13.0"
resolved "https://registry.npmjs.org/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de"
babel-plugin-syntax-dynamic-import@^6.18.0:
babel-plugin-syntax-dynamic-import@6.18.0:
version "6.18.0"
resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da"
@ -557,7 +556,7 @@ babel-plugin-transform-es2015-block-scoped-functions@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-block-scoping@^6.22.0:
babel-plugin-transform-es2015-block-scoping@^6.22.0, babel-plugin-transform-es2015-block-scoping@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz#e48895cf0b375be148cd7c8879b422707a053b51"
dependencies:
@ -567,7 +566,7 @@ babel-plugin-transform-es2015-block-scoping@^6.22.0:
babel-types "^6.23.0"
lodash "^4.2.0"
babel-plugin-transform-es2015-classes@^6.22.0:
babel-plugin-transform-es2015-classes@^6.22.0, babel-plugin-transform-es2015-classes@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz#49b53f326202a2fd1b3bbaa5e2edd8a4f78643c1"
dependencies:
@ -588,7 +587,7 @@ babel-plugin-transform-es2015-computed-properties@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
babel-plugin-transform-es2015-destructuring@^6.22.0:
babel-plugin-transform-es2015-destructuring@^6.22.0, babel-plugin-transform-es2015-destructuring@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d"
dependencies:
@ -601,7 +600,7 @@ babel-plugin-transform-es2015-duplicate-keys@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
babel-plugin-transform-es2015-for-of@^6.22.0:
babel-plugin-transform-es2015-for-of@^6.22.0, babel-plugin-transform-es2015-for-of@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691"
dependencies:
@ -621,7 +620,7 @@ babel-plugin-transform-es2015-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-modules-amd@^6.24.0:
babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.0:
version "6.24.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.0.tgz#a1911fb9b7ec7e05a43a63c5995007557bcf6a2e"
dependencies:
@ -629,7 +628,7 @@ babel-plugin-transform-es2015-modules-amd@^6.24.0:
babel-runtime "^6.22.0"
babel-template "^6.22.0"
babel-plugin-transform-es2015-modules-commonjs@6.24.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.0:
babel-plugin-transform-es2015-modules-commonjs@6.24.0, babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.0:
version "6.24.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.0.tgz#e921aefb72c2cc26cb03d107626156413222134f"
dependencies:
@ -638,7 +637,7 @@ babel-plugin-transform-es2015-modules-commonjs@6.24.0, babel-plugin-transform-es
babel-template "^6.23.0"
babel-types "^6.23.0"
babel-plugin-transform-es2015-modules-systemjs@^6.22.0:
babel-plugin-transform-es2015-modules-systemjs@^6.22.0, babel-plugin-transform-es2015-modules-systemjs@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz#ae3469227ffac39b0310d90fec73bfdc4f6317b0"
dependencies:
@ -646,7 +645,7 @@ babel-plugin-transform-es2015-modules-systemjs@^6.22.0:
babel-runtime "^6.22.0"
babel-template "^6.23.0"
babel-plugin-transform-es2015-modules-umd@^6.24.0:
babel-plugin-transform-es2015-modules-umd@^6.23.0, babel-plugin-transform-es2015-modules-umd@^6.24.0:
version "6.24.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.0.tgz#fd5fa63521cae8d273927c3958afd7c067733450"
dependencies:
@ -661,7 +660,7 @@ babel-plugin-transform-es2015-object-super@^6.22.0:
babel-helper-replace-supers "^6.22.0"
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-parameters@^6.22.0:
babel-plugin-transform-es2015-parameters@^6.22.0, babel-plugin-transform-es2015-parameters@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz#3a2aabb70c8af945d5ce386f1a4250625a83ae3b"
dependencies:
@ -699,7 +698,7 @@ babel-plugin-transform-es2015-template-literals@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol@^6.22.0:
babel-plugin-transform-es2015-typeof-symbol@^6.22.0, babel-plugin-transform-es2015-typeof-symbol@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372"
dependencies:
@ -763,9 +762,9 @@ babel-plugin-transform-react-jsx@^6.23.0:
babel-plugin-syntax-jsx "^6.8.0"
babel-runtime "^6.22.0"
babel-plugin-transform-react-remove-prop-types@0.3.2:
version "0.3.2"
resolved "https://registry.npmjs.org/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.3.2.tgz#6da8d834c6d7ad8ab02f956509790cfaa01ffe19"
babel-plugin-transform-react-remove-prop-types@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.0.tgz#f63840e7953563d661be8c647b094d74d7363f17"
babel-plugin-transform-regenerator@^6.22.0:
version "6.22.0"
@ -790,7 +789,41 @@ babel-plugin-transform-strict-mode@^6.22.0:
babel-runtime "^6.22.0"
babel-types "^6.22.0"
babel-preset-es2015@6.24.0, babel-preset-es2015@^6.24.0:
babel-preset-env@1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.3.3.tgz#5913407784e3d98de2aa814a3ef9059722b34e0b"
dependencies:
babel-plugin-check-es2015-constants "^6.22.0"
babel-plugin-syntax-trailing-function-commas "^6.22.0"
babel-plugin-transform-async-to-generator "^6.22.0"
babel-plugin-transform-es2015-arrow-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoped-functions "^6.22.0"
babel-plugin-transform-es2015-block-scoping "^6.23.0"
babel-plugin-transform-es2015-classes "^6.23.0"
babel-plugin-transform-es2015-computed-properties "^6.22.0"
babel-plugin-transform-es2015-destructuring "^6.23.0"
babel-plugin-transform-es2015-duplicate-keys "^6.22.0"
babel-plugin-transform-es2015-for-of "^6.23.0"
babel-plugin-transform-es2015-function-name "^6.22.0"
babel-plugin-transform-es2015-literals "^6.22.0"
babel-plugin-transform-es2015-modules-amd "^6.22.0"
babel-plugin-transform-es2015-modules-commonjs "^6.23.0"
babel-plugin-transform-es2015-modules-systemjs "^6.23.0"
babel-plugin-transform-es2015-modules-umd "^6.23.0"
babel-plugin-transform-es2015-object-super "^6.22.0"
babel-plugin-transform-es2015-parameters "^6.23.0"
babel-plugin-transform-es2015-shorthand-properties "^6.22.0"
babel-plugin-transform-es2015-spread "^6.22.0"
babel-plugin-transform-es2015-sticky-regex "^6.22.0"
babel-plugin-transform-es2015-template-literals "^6.22.0"
babel-plugin-transform-es2015-typeof-symbol "^6.23.0"
babel-plugin-transform-es2015-unicode-regex "^6.22.0"
babel-plugin-transform-exponentiation-operator "^6.22.0"
babel-plugin-transform-regenerator "^6.22.0"
browserslist "^1.4.0"
invariant "^2.2.2"
babel-preset-es2015@6.24.0:
version "6.24.0"
resolved "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.0.tgz#c162d68b1932696e036cd3110dc1ccd303d2673a"
dependencies:
@ -819,19 +852,6 @@ babel-preset-es2015@6.24.0, babel-preset-es2015@^6.24.0:
babel-plugin-transform-es2015-unicode-regex "^6.22.0"
babel-plugin-transform-regenerator "^6.22.0"
babel-preset-es2016@^6.22.0:
version "6.22.0"
resolved "https://registry.npmjs.org/babel-preset-es2016/-/babel-preset-es2016-6.22.0.tgz#b061aaa3983d40c9fbacfa3743b5df37f336156c"
dependencies:
babel-plugin-transform-exponentiation-operator "^6.22.0"
babel-preset-es2017@^6.22.0:
version "6.22.0"
resolved "https://registry.npmjs.org/babel-preset-es2017/-/babel-preset-es2017-6.22.0.tgz#de2f9da5a30c50d293fb54a0ba15d6ddc573f0f2"
dependencies:
babel-plugin-syntax-trailing-function-commas "^6.22.0"
babel-plugin-transform-async-to-generator "^6.22.0"
babel-preset-flow@^6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz#e71218887085ae9a24b5be4169affb599816c49d"
@ -850,14 +870,6 @@ babel-preset-jest@^19.0.0:
dependencies:
babel-plugin-jest-hoist "^19.0.0"
babel-preset-latest@6.24.0:
version "6.24.0"
resolved "https://registry.npmjs.org/babel-preset-latest/-/babel-preset-latest-6.24.0.tgz#a68d20f509edcc5d7433a48dfaebf7e4f2cd4cb7"
dependencies:
babel-preset-es2015 "^6.24.0"
babel-preset-es2016 "^6.22.0"
babel-preset-es2017 "^6.22.0"
babel-preset-react@6.23.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.23.0.tgz#eb7cee4de98a3f94502c28565332da9819455195"
@ -888,6 +900,16 @@ babel-runtime@6.23.0, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtim
core-js "^2.4.0"
regenerator-runtime "^0.10.0"
babel-template@6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333"
dependencies:
babel-runtime "^6.22.0"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babylon "^6.11.0"
lodash "^4.2.0"
babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0, babel-template@^6.7.0:
version "6.23.0"
resolved "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz#04d4f270adbb3aa704a8143ae26faa529238e638"
@ -898,16 +920,6 @@ babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.23.0, babel-te
babylon "^6.11.0"
lodash "^4.2.0"
babel-template@^6.24.1:
version "6.24.1"
resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333"
dependencies:
babel-runtime "^6.22.0"
babel-traverse "^6.24.1"
babel-types "^6.24.1"
babylon "^6.11.0"
lodash "^4.2.0"
babel-traverse@6.21.0:
version "6.21.0"
resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad"
@ -1111,6 +1123,13 @@ browserify-zlib@^0.1.4:
dependencies:
pako "~0.2.0"
browserslist@^1.4.0:
version "1.7.7"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9"
dependencies:
caniuse-db "^1.0.30000639"
electron-to-chromium "^1.2.7"
bser@1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/bser/-/bser-1.0.2.tgz#381116970b2a6deea5646dd15dd7278444b56169"
@ -1181,6 +1200,10 @@ camelcase@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
caniuse-db@^1.0.30000639:
version "1.0.30000650"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000650.tgz#615f564d367533d32b82d72ada09661e75386bab"
case-sensitive-paths-webpack-plugin@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.0.0.tgz#60142d7d0beabdb35676ef0aeace3027da0578ba"
@ -1242,9 +1265,9 @@ chokidar@^1.4.3, chokidar@^1.6.1:
optionalDependencies:
fsevents "^1.0.0"
chromedriver@2.28.0:
version "2.28.0"
resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.28.0.tgz#ea0c383621dd27db340c612b85fe39414c16ec79"
chromedriver@2.29.0:
version "2.29.0"
resolved "https://registry.npmjs.org/chromedriver/-/chromedriver-2.29.0.tgz#e3fd8b3c08dce2562b80ef1b0b846597659d0cc3"
dependencies:
adm-zip "^0.4.7"
kew "^0.7.0"
@ -1703,6 +1726,10 @@ ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
electron-to-chromium@^1.2.7:
version "1.3.3"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.3.tgz#651eb63fe89f39db70ffc8dbd5d9b66958bc6a0e"
elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
@ -1981,7 +2008,7 @@ esutils@^2.0.0, esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
etag@~1.8.0:
etag@1.8.0, etag@~1.8.0:
version "1.8.0"
resolved "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051"
@ -2066,9 +2093,9 @@ fb-watchman@^2.0.0:
dependencies:
bser "^2.0.0"
fbjs@^0.8.1, fbjs@^0.8.4:
version "0.8.9"
resolved "https://registry.npmjs.org/fbjs/-/fbjs-0.8.9.tgz#180247fbd347dcc9004517b904f865400a0c8f14"
fbjs@^0.8.9:
version "0.8.12"
resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04"
dependencies:
core-js "^1.0.0"
isomorphic-fetch "^2.1.1"
@ -2340,17 +2367,7 @@ glob-promise@3.1.0:
version "3.1.0"
resolved "https://registry.npmjs.org/glob-promise/-/glob-promise-3.1.0.tgz#198882a3817be7dc2c55f92623aa9e7b3f82d1eb"
glob@^6.0.1:
version "6.0.4"
resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
dependencies:
inflight "^1.0.4"
inherits "2"
minimatch "2 || 3"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
glob@7.1.1, glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
version "7.1.1"
resolved "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
@ -2361,6 +2378,16 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^6.0.1:
version "6.0.4"
resolved "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
dependencies:
inflight "^1.0.4"
inherits "2"
minimatch "2 || 3"
once "^1.3.0"
path-is-absolute "^1.0.0"
global@^4.3.0:
version "4.3.1"
resolved "https://registry.npmjs.org/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df"
@ -2613,7 +2640,7 @@ interpret@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c"
invariant@^2.2.0:
invariant@^2.2.0, invariant@^2.2.2:
version "2.2.2"
resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360"
dependencies:
@ -4042,6 +4069,18 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
prop-types@15.5.7:
version "15.5.7"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.7.tgz#231c4f29cdd82e355011d4889386ca9059544dd1"
dependencies:
fbjs "^0.8.9"
prop-types@^15.5.2, prop-types@~15.5.0:
version "15.5.6"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.6.tgz#797a915b1714b645ebb7c5d6cc690346205bd2aa"
dependencies:
fbjs "^0.8.9"
prr@~0.0.0:
version "0.0.0"
resolved "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a"
@ -4112,13 +4151,14 @@ react-deep-force-update@^2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/react-deep-force-update/-/react-deep-force-update-2.0.1.tgz#4f7f6c12c3e7de42f345992a3c518236fa1ecad3"
react-dom@15.4.2:
version "15.4.2"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-15.4.2.tgz#015363f05b0a1fd52ae9efdd3a0060d90695208f"
react-dom@15.5.3:
version "15.5.3"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.3.tgz#2ee127ce942df55da53111ae303316e68072b5c5"
dependencies:
fbjs "^0.8.1"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
prop-types "~15.5.0"
react-hot-loader@3.0.0-beta.6:
version "3.0.0-beta.6"
@ -4137,13 +4177,14 @@ react-proxy@^3.0.0-alpha.0:
dependencies:
lodash "^4.6.1"
react@15.4.2:
version "15.4.2"
resolved "https://registry.npmjs.org/react/-/react-15.4.2.tgz#41f7991b26185392ba9bae96c8889e7e018397ef"
react@15.5.3:
version "15.5.3"
resolved "https://registry.yarnpkg.com/react/-/react-15.5.3.tgz#84055382c025dec4e3b902bb61a8697cc79c1258"
dependencies:
fbjs "^0.8.4"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
prop-types "^15.5.2"
read-pkg-up@^1.0.1:
version "1.0.1"