diff --git a/package.json b/package.json
index f64dc823..ef5813ba 100644
--- a/package.json
+++ b/package.json
@@ -67,6 +67,7 @@
"is-windows-bash": "1.0.3",
"json-loader": "0.5.4",
"loader-utils": "1.1.0",
+ "md5-file": "3.1.1",
"minimist": "1.2.0",
"mitt": "1.1.0",
"mkdirp-then": "1.2.0",
diff --git a/server/build/index.js b/server/build/index.js
index 0fcff294..e13d36ff 100644
--- a/server/build/index.js
+++ b/server/build/index.js
@@ -5,14 +5,15 @@ import uuid from 'uuid'
import del from 'del'
import webpack from './webpack'
import replaceCurrentBuild from './replace'
+import md5File from 'md5-file/promise'
export default async function build (dir) {
const buildDir = join(tmpdir(), uuid.v4())
const compiler = await webpack(dir, { buildDir })
try {
- const webpackStats = await runCompiler(compiler)
- await writeBuildStats(buildDir, webpackStats)
+ await runCompiler(compiler)
+ await writeBuildStats(buildDir)
await writeBuildId(buildDir)
} catch (err) {
console.error(`> Failed to build on ${buildDir}`)
@@ -44,17 +45,18 @@ function runCompiler (compiler) {
})
}
-async function writeBuildStats (dir, webpackStats) {
- const chunkHashMap = {}
- webpackStats.chunks
- // We are not interested about pages
- .filter(({ files }) => !/^bundles/.test(files[0]))
- .forEach(({ hash, files }) => {
- chunkHashMap[files[0]] = { hash }
- })
-
+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(dir, '.next', 'app.js'))
+ }
+ }
const buildStatsPath = join(dir, '.next', 'build-stats.json')
- await fs.writeFile(buildStatsPath, JSON.stringify(chunkHashMap), 'utf8')
+ await fs.writeFile(buildStatsPath, JSON.stringify(assetHashMap), 'utf8')
}
async function writeBuildId (dir) {
diff --git a/server/build/plugins/combine-assets-plugin.js b/server/build/plugins/combine-assets-plugin.js
new file mode 100644
index 00000000..959c14cd
--- /dev/null
+++ b/server/build/plugins/combine-assets-plugin.js
@@ -0,0 +1,26 @@
+// This plugin combines a set of assets into a single asset
+// This should be only used with text assets,
+// otherwise the result is unpredictable.
+export default class CombineAssetsPlugin {
+ constructor ({ input, output }) {
+ this.input = input
+ this.output = output
+ }
+
+ apply (compiler) {
+ compiler.plugin('after-compile', (compilation, callback) => {
+ let newSource = ''
+ this.input.forEach((name) => {
+ newSource += `${compilation.assets[name].source()}\n`
+ delete compilation.assets[name]
+ })
+
+ compilation.assets[this.output] = {
+ source: () => newSource,
+ size: () => newSource.length
+ }
+
+ callback()
+ })
+ }
+}
diff --git a/server/build/webpack.js b/server/build/webpack.js
index e4b0403d..0aff98de 100644
--- a/server/build/webpack.js
+++ b/server/build/webpack.js
@@ -7,6 +7,7 @@ import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
import CaseSensitivePathPlugin from 'case-sensitive-paths-webpack-plugin'
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
import JsonPagesPlugin from './plugins/json-pages-plugin'
+import CombineAssetsPlugin from './plugins/combine-assets-plugin'
import getConfig from '../config'
import * as babelCore from 'babel-core'
import findBabelConfig from './babel/find-config'
@@ -119,6 +120,10 @@ export default async function createCompiler (dir, { dev = false, quiet = false,
}
} else {
plugins.push(
+ new CombineAssetsPlugin({
+ input: ['commons.js', 'main.js'],
+ output: 'app.js'
+ }),
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
sourceMap: false
diff --git a/server/document.js b/server/document.js
index 5bd502af..d169cfe4 100644
--- a/server/document.js
+++ b/server/document.js
@@ -59,16 +59,36 @@ export class NextScript extends Component {
_documentProps: PropTypes.any
}
- getChunkScript (filename) {
+ getChunkScript (filename, additionalProps = {}) {
const { __NEXT_DATA__ } = this.context._documentProps
let { buildStats } = __NEXT_DATA__
const hash = buildStats ? buildStats[filename].hash : '-'
return (
-
+
)
}
+ getScripts () {
+ const { dev } = this.context._documentProps
+ if (dev) {
+ return (
+
+ { this.getChunkScript('commons.js') }
+ { this.getChunkScript('main.js') }
+
+ )
+ }
+
+ // In the production mode, we have a single asset with all the JS content.
+ // So, we can load the script with async
+ return this.getChunkScript('app.js', { async: true })
+ }
+
render () {
const { staticMarkup, __NEXT_DATA__ } = this.context._documentProps
@@ -76,8 +96,7 @@ export class NextScript extends Component {
{staticMarkup ? null : }
- { staticMarkup ? null : this.getChunkScript('commons.js') }
- { staticMarkup ? null : this.getChunkScript('main.js') }
+ {staticMarkup ? null : this.getScripts()}
}
}
diff --git a/server/index.js b/server/index.js
index f08a9fec..26c58ab5 100644
--- a/server/index.js
+++ b/server/index.js
@@ -102,6 +102,12 @@ export default class Server {
await this.serveStatic(req, res, p)
},
+ '/_next/:hash/app.js': async (req, res, params) => {
+ this.handleBuildHash('app.js', params.hash, res)
+ const p = join(this.dir, '.next/app.js')
+ await this.serveStatic(req, res, p)
+ },
+
'/_next/:buildId/pages/:path*': async (req, res, params) => {
if (!this.handleBuildId(params.buildId, res)) {
res.setHeader('Content-Type', 'application/json')
diff --git a/yarn.lock b/yarn.lock
index 498e858e..386b18e2 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -455,13 +455,13 @@ babel-plugin-check-es2015-constants@^6.22.0:
dependencies:
babel-runtime "^6.22.0"
-babel-plugin-istanbul@4.0.0, babel-plugin-istanbul@^4.0.0:
- version "4.0.0"
- resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.0.0.tgz#36bde8fbef4837e5ff0366531a2beabd7b1ffa10"
+babel-plugin-istanbul@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.1.tgz#c12de0fc6fe42adfb16be56f1ad11e4a9782eca9"
dependencies:
find-up "^2.1.0"
- istanbul-lib-instrument "^1.4.2"
- test-exclude "^4.0.0"
+ istanbul-lib-instrument "^1.6.2"
+ test-exclude "^4.0.3"
babel-plugin-istanbul@^3.0.0:
version "3.0.0"
@@ -472,6 +472,14 @@ babel-plugin-istanbul@^3.0.0:
object-assign "^4.1.0"
test-exclude "^3.2.2"
+babel-plugin-istanbul@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-4.0.0.tgz#36bde8fbef4837e5ff0366531a2beabd7b1ffa10"
+ dependencies:
+ find-up "^2.1.0"
+ istanbul-lib-instrument "^1.4.2"
+ test-exclude "^4.0.0"
+
babel-plugin-jest-hoist@^18.0.0:
version "18.0.0"
resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-18.0.0.tgz#4150e70ecab560e6e7344adc849498072d34e12a"
@@ -1301,9 +1309,9 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-concat-stream@^1.4.6:
+concat-stream@^1.5.2:
version "1.6.0"
- resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
+ resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
inherits "^2.0.3"
readable-stream "^2.2.2"
@@ -1581,6 +1589,13 @@ doctrine@^1.2.2:
esutils "^2.0.2"
isarray "^1.0.0"
+doctrine@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
+ dependencies:
+ esutils "^2.0.2"
+ isarray "^1.0.0"
+
dom-serializer@0, dom-serializer@~0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -1797,9 +1812,9 @@ eslint-config-standard-jsx@3.3.0:
version "3.3.0"
resolved "https://registry.npmjs.org/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.3.0.tgz#cab0801a15a360bf63facb97ab22fbdd88d8a5e0"
-eslint-config-standard@7.0.0:
- version "7.0.0"
- resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-7.0.0.tgz#4f161bc65695e4bc61331c55b9eeaca458cd99c6"
+eslint-config-standard@7.1.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-7.1.0.tgz#47e769ea0739f5b2d5693b1a501c21c9650fafcf"
eslint-plugin-promise@~3.4.0:
version "3.4.2"
@@ -1817,17 +1832,18 @@ eslint-plugin-standard@~2.0.1:
version "2.0.1"
resolved "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3"
-eslint@~3.15.0:
- version "3.15.0"
- resolved "https://registry.npmjs.org/eslint/-/eslint-3.15.0.tgz#bdcc6a6c5ffe08160e7b93c066695362a91e30f2"
+eslint@~3.18.0:
+ version "3.18.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.18.0.tgz#647e985c4ae71502d20ac62c109f66d5104c8a4b"
dependencies:
babel-code-frame "^6.16.0"
chalk "^1.1.3"
- concat-stream "^1.4.6"
+ concat-stream "^1.5.2"
debug "^2.1.1"
- doctrine "^1.2.2"
+ doctrine "^2.0.0"
escope "^3.6.0"
espree "^3.4.0"
+ esquery "^1.0.0"
estraverse "^4.2.0"
esutils "^2.0.2"
file-entry-cache "^2.0.0"
@@ -1871,6 +1887,12 @@ esprima@^3.1.1:
version "3.1.3"
resolved "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+esquery@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
+ dependencies:
+ estraverse "^4.0.0"
+
esrecurse@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220"
@@ -1882,7 +1904,7 @@ estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
-estraverse@^4.1.1, estraverse@^4.2.0:
+estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
@@ -2730,6 +2752,18 @@ istanbul-lib-instrument@^1.1.1, istanbul-lib-instrument@^1.1.4, istanbul-lib-ins
istanbul-lib-coverage "^1.0.0"
semver "^5.3.0"
+istanbul-lib-instrument@^1.6.2:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.6.2.tgz#dac644f358f51efd6113536d7070959a0111f73b"
+ dependencies:
+ babel-generator "^6.18.0"
+ babel-template "^6.16.0"
+ babel-traverse "^6.18.0"
+ babel-types "^6.18.0"
+ babylon "^6.13.0"
+ istanbul-lib-coverage "^1.0.0"
+ semver "^5.3.0"
+
istanbul-lib-report@^1.0.0-alpha.3:
version "1.0.0-alpha.3"
resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.0.0-alpha.3.tgz#32d5f6ec7f33ca3a602209e278b2e6ff143498af"
@@ -3231,6 +3265,10 @@ makeerror@1.0.x:
dependencies:
tmpl "1.0.x"
+md5-file@3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/md5-file/-/md5-file-3.1.1.tgz#db3c92c09bbda5c2de883fa5490dd711fddbbab9"
+
md5-hex@^1.2.0:
version "1.3.0"
resolved "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4"
@@ -3425,7 +3463,7 @@ node-libs-browser@^2.0.0:
util "^0.10.3"
vm-browserify "0.0.4"
-node-notifier@5.1.2:
+node-notifier@5.1.2, node-notifier@^5.0.1:
version "5.1.2"
resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.1.2.tgz#2fa9e12605fa10009d44549d6fcd8a63dde0e4ff"
dependencies:
@@ -3434,15 +3472,6 @@ node-notifier@5.1.2:
shellwords "^0.1.0"
which "^1.2.12"
-node-notifier@^5.0.1:
- version "5.0.2"
- resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-5.0.2.tgz#4438449fe69e321f941cef943986b0797032701b"
- dependencies:
- growly "^1.3.0"
- semver "^5.3.0"
- shellwords "^0.1.0"
- which "^1.2.12"
-
node-pre-gyp@^0.6.29:
version "0.6.33"
resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.33.tgz#640ac55198f6a925972e0c16c4ac26a034d5ecc9"
@@ -3830,11 +3859,11 @@ public-encrypt@^4.0.0:
parse-asn1 "^5.0.0"
randombytes "^2.0.1"
-punycode@1.3.2, punycode@^1.2.4:
+punycode@1.3.2:
version "1.3.2"
resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
-punycode@^1.4.1:
+punycode@^1.2.4, punycode@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
@@ -4258,13 +4287,13 @@ sntp@1.x.x:
dependencies:
hoek "2.x.x"
-source-list-map@~0.1.7:
- version "0.1.8"
- resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106"
+source-list-map@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.0.1.tgz#cc1fc17122ae0a51978024c2cc0f8c35659026b8"
-source-map-support@0.4.13:
- version "0.4.13"
- resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.13.tgz#9782e6f7deb424d5f173327a1879eb46453bdcd4"
+source-map-support@0.4.14:
+ version "0.4.14"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef"
dependencies:
source-map "^0.5.6"
@@ -4352,12 +4381,12 @@ standard-engine@~5.4.0:
minimist "^1.1.0"
pkg-conf "^2.0.0"
-standard@9.0.0:
- version "9.0.0"
- resolved "https://registry.npmjs.org/standard/-/standard-9.0.0.tgz#58b2acad4dc33823a7477568033c973fc5b6a995"
+standard@9.0.2:
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/standard/-/standard-9.0.2.tgz#9bd3b9467492e212b1914d78553943ff9b48fd99"
dependencies:
- eslint "~3.15.0"
- eslint-config-standard "7.0.0"
+ eslint "~3.18.0"
+ eslint-config-standard "7.1.0"
eslint-config-standard-jsx "3.3.0"
eslint-plugin-promise "~3.4.0"
eslint-plugin-react "~6.9.0"
@@ -4530,6 +4559,16 @@ test-exclude@^4.0.0:
read-pkg-up "^1.0.1"
require-main-filename "^1.0.1"
+test-exclude@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.0.3.tgz#86a13ce3effcc60e6c90403cf31a27a60ac6c4e7"
+ dependencies:
+ arrify "^1.0.1"
+ micromatch "^2.3.11"
+ object-assign "^4.1.0"
+ read-pkg-up "^1.0.1"
+ require-main-filename "^1.0.1"
+
text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@@ -4622,7 +4661,7 @@ ua-parser-js@^0.7.9:
version "0.7.12"
resolved "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb"
-uglify-js@^2.6, uglify-js@^2.7.5:
+uglify-js@^2.6, uglify-js@^2.8.5:
version "2.8.7"
resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.7.tgz#e0391911507b6d2e05697a528f1686e90a11b160"
dependencies:
@@ -4717,9 +4756,9 @@ watch@~0.10.0:
version "0.10.0"
resolved "https://registry.npmjs.org/watch/-/watch-0.10.0.tgz#77798b2da0f9910d595f1ace5b0c2258521f21dc"
-watchpack@^1.2.0:
+watchpack@^1.3.1:
version "1.3.1"
- resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87"
dependencies:
async "^2.1.2"
chokidar "^1.4.3"
@@ -4764,16 +4803,16 @@ webpack-hot-middleware@2.17.1:
querystring "^0.2.0"
strip-ansi "^3.0.0"
-webpack-sources@^0.1.4:
- version "0.1.4"
- resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.4.tgz#ccc2c817e08e5fa393239412690bb481821393cd"
+webpack-sources@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.0.tgz#fea93ba840f16cdd3f246f0ee95f88a9492c69fb"
dependencies:
- source-list-map "~0.1.7"
+ source-list-map "^1.0.1"
source-map "~0.5.3"
-webpack@2.2.1:
- version "2.2.1"
- resolved "https://registry.npmjs.org/webpack/-/webpack-2.2.1.tgz#7bb1d72ae2087dd1a4af526afec15eed17dda475"
+webpack@2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.3.1.tgz#55bce8baffe7c1f9dc3029adc048643b448318a8"
dependencies:
acorn "^4.0.4"
acorn-dynamic-import "^2.0.0"
@@ -4791,9 +4830,9 @@ webpack@2.2.1:
source-map "^0.5.3"
supports-color "^3.1.0"
tapable "~0.2.5"
- uglify-js "^2.7.5"
- watchpack "^1.2.0"
- webpack-sources "^0.1.4"
+ uglify-js "^2.8.5"
+ watchpack "^1.3.1"
+ webpack-sources "^0.2.0"
yargs "^6.0.0"
whatwg-encoding@^1.0.1: