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

Load the main JS bundle in production with async (#1485)

* Use a webpack plugin to combine assets.

* Add comments and make this releseable.

* Fix some typos.

* Fix some typos.
This commit is contained in:
Arunoda Susiripala 2017-03-24 13:21:34 +05:30 committed by GitHub
parent 377a614f04
commit 32af8294a7
7 changed files with 166 additions and 68 deletions

View file

@ -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",

View file

@ -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) {

View file

@ -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()
})
}
}

View file

@ -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

View file

@ -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 (
<script type='text/javascript' src={`/_next/${hash}/${filename}`} defer />
<script
type='text/javascript'
src={`/_next/${hash}/${filename}`}
{...additionalProps}
/>
)
}
getScripts () {
const { dev } = this.context._documentProps
if (dev) {
return (
<div>
{ this.getChunkScript('commons.js') }
{ this.getChunkScript('main.js') }
</div>
)
}
// 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 : <script dangerouslySetInnerHTML={{
__html: `__NEXT_DATA__ = ${htmlescape(__NEXT_DATA__)}; module={};`
}} />}
{ staticMarkup ? null : this.getChunkScript('commons.js') }
{ staticMarkup ? null : this.getChunkScript('main.js') }
{staticMarkup ? null : this.getScripts()}
</div>
}
}

View file

@ -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')

143
yarn.lock
View file

@ -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: