Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load the main JS bundle in production with async #1485

Merged
merged 4 commits into from
Mar 24, 2017
Merged
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -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",
26 changes: 14 additions & 12 deletions server/build/index.js
Original file line number Diff line number Diff line change
@@ -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 the hashes in the webpack chunks.
// That's because the "app.js" is not tight with a chunk.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is not tight with a chunk.

is not tied to a chunk is more correct here right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

// It's created with merging the 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) {
26 changes: 26 additions & 0 deletions server/build/plugins/combine-assets-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// This pulgin combines a set of assets into a single asset
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pulgin => plugin

// 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()
})
}
}
5 changes: 5 additions & 0 deletions server/build/webpack.js
Original file line number Diff line number Diff line change
@@ -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
27 changes: 23 additions & 4 deletions server/document.js
Original file line number Diff line number Diff line change
@@ -59,25 +59,44 @@ 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

return <div>
{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>
}
}
6 changes: 6 additions & 0 deletions server/index.js
Original file line number Diff line number Diff line change
@@ -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')
Loading