Skip to content

Commit e182c8e

Browse files
committed
Split React into a separate chunk
1 parent 6267992 commit e182c8e

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

config/webpack.config.prod.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var autoprefixer = require('autoprefixer');
1212
var webpack = require('webpack');
1313
var HtmlWebpackPlugin = require('html-webpack-plugin');
1414
var ExtractTextPlugin = require('extract-text-webpack-plugin');
15+
var WebpackMd5Hash = require('webpack-md5-hash');
1516
var url = require('url');
1617
var paths = require('./paths');
1718

@@ -25,7 +26,13 @@ if (!publicPath.endsWith('/')) {
2526
module.exports = {
2627
bail: true,
2728
devtool: 'source-map',
28-
entry: path.join(paths.appSrc, 'index'),
29+
entry: {
30+
// Split app into the main and vendor bundles.
31+
// Vendor will contain React by default but we might want to
32+
// dynamically choose to add something else from node_modules.
33+
main: path.join(paths.appSrc, 'index'),
34+
vendor: ['react', 'react-dom'],
35+
},
2936
output: {
3037
path: paths.appBuild,
3138
filename: '[name].[chunkhash:8].js',
@@ -92,10 +99,53 @@ module.exports = {
9299
return [autoprefixer];
93100
},
94101
plugins: [
102+
// Create two common chunks:
103+
// - "vendor" chunk is declared in "entry" above.
104+
// - "manifest" is a built-in Webpack chunk with its runtime.
105+
// This would enable us to enable long-term caching.
106+
// The tricky part is that "manifest" will contain the filenames
107+
// of the other chunks. This is why we want to embed it into HTML.
108+
// Otherwise, changes in any chunk will cause manifest to change,
109+
// and thus if manifest isn't separated, its parent will also change.
110+
// Relevant discussion: https://github.com/webpack/webpack/issues/1315
111+
new webpack.optimize.CommonsChunkPlugin({
112+
names: ['vendor', 'manifest']
113+
}),
114+
// Fixes deterministic hashes so that changes to CSS don't invalidate JS.
115+
new WebpackMd5Hash(),
116+
// Avoids extra request for the manifest that contains webpack runtime
117+
// by embedding it right into HTML as an inline <script>.
118+
function embedManifestIntoHTML() {
119+
this.plugin('compilation', (compilation) => {
120+
compilation.plugin('html-webpack-plugin-before-html-processing', (data, cb) => {
121+
var manifestSource;
122+
// Find the manifest chunk generated by webpack,
123+
// grab its source, and embed it into generated HTML.
124+
Object.keys(compilation.assets).forEach(key => {
125+
if (key.indexOf('manifest.') !== 0) {
126+
return;
127+
}
128+
var children = compilation.assets[key].children;
129+
if (!children || !children[0]) {
130+
return;
131+
}
132+
delete compilation.assets[key];
133+
manifestSource = children[0]._value;
134+
});
135+
data.html = data.html.replace(
136+
'</body>',
137+
'<script>' + manifestSource + '</script></body>'
138+
);
139+
cb()
140+
})
141+
})
142+
},
95143
new HtmlWebpackPlugin({
96144
inject: true,
97145
template: paths.appHtml,
98146
favicon: paths.appFavicon,
147+
chunksSortMode: 'dependency', // Ensure vendor chunk comes first.
148+
excludeChunks: ['manifest'], // We embedded it earlier.
99149
minify: {
100150
removeComments: true,
101151
collapseWhitespace: true,

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@
5757
"style-loader": "0.13.1",
5858
"url-loader": "0.5.7",
5959
"webpack": "1.13.1",
60-
"webpack-dev-server": "1.14.1"
60+
"webpack-dev-server": "1.14.1",
61+
"webpack-md5-hash": "0.0.5"
6162
},
6263
"devDependencies": {
6364
"bundle-deps": "1.0.0",

0 commit comments

Comments
 (0)