From 76cd9ea32b80b8e6c49e7fe5597e8cc5e0e1dfa7 Mon Sep 17 00:00:00 2001 From: Shriyans Date: Sun, 21 May 2017 23:41:50 +0900 Subject: [PATCH 1/4] added vendor to paths --- packages/react-scripts/config/paths.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 42ec8374a15..5934e73fa8d 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -55,6 +55,7 @@ module.exports = { appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveApp('src/index.js'), + appVendorJs: resolveApp('src/vendor.js'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), yarnLockFile: resolveApp('yarn.lock'), @@ -75,6 +76,7 @@ module.exports = { appPublic: resolveApp('public'), appHtml: resolveApp('public/index.html'), appIndexJs: resolveApp('src/index.js'), + appVendorJs: resolveApp('src/vendor.js'), appPackageJson: resolveApp('package.json'), appSrc: resolveApp('src'), yarnLockFile: resolveApp('yarn.lock'), @@ -104,6 +106,7 @@ if ( appPublic: resolveOwn('template/public'), appHtml: resolveOwn('template/public/index.html'), appIndexJs: resolveOwn('template/src/index.js'), + appVendorJs: resolveOwn('template/src/vendor.js'), appPackageJson: resolveOwn('package.json'), appSrc: resolveOwn('template/src'), yarnLockFile: resolveOwn('template/yarn.lock'), From fa83243da061b3414b1df0e1ac4160483ce48d65 Mon Sep 17 00:00:00 2001 From: Shriyans Date: Sun, 21 May 2017 23:56:14 +0900 Subject: [PATCH 2/4] added support for vendor bundling --- .../config/webpack.config.prod.js | 29 +++++++++++++++++-- packages/react-scripts/package.json | 1 + 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 3de2775e030..37a795eb40c 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -12,7 +12,9 @@ const autoprefixer = require('autoprefixer'); const path = require('path'); +const fs = require('fs'); const webpack = require('webpack'); +const WebpackMd5Hash = require('webpack-md5-hash'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); @@ -53,6 +55,18 @@ const extractTextPluginOptions = shouldUseRelativeAssetPaths ? // Making sure that the publicPath goes back to to build folder. { publicPath: Array(cssFilename.split('/').length).join('../') } : {}; +// Check if vendor file exists +const checkIfVendorFileExists = fs.existsSync(paths.appVendorJs); +// If the vendor file exists, add an entry point for vendor, +// and a seperate entry for polyfills and app index file, +// otherwise keep only polyfills and app index. +const appEntryFiles = [require.resolve('./polyfills'), paths.appIndexJs]; +const entryFiles = checkIfVendorFileExists + ? { + vendor: paths.appVendorJs, + main: appEntryFiles, + } + : appEntryFiles; // This is the production configuration. // It compiles slowly and is focused on producing a fast and minimal bundle. @@ -63,8 +77,8 @@ module.exports = { // We generate sourcemaps in production. This is slow but gives good results. // You can exclude the *.map files from the build during deployment. devtool: 'source-map', - // In production, we only want to load the polyfills and the app code. - entry: [require.resolve('./polyfills'), paths.appIndexJs], + // Add the entry point based on whether vendor file exists. + entry: entryFiles, output: { // The build folder. path: paths.appBuild, @@ -278,6 +292,17 @@ module.exports = { // It is absolutely essential that NODE_ENV was set to production here. // Otherwise React will be compiled in the very slow development mode. new webpack.DefinePlugin(env.stringified), + // We need to extract out the runtime into a separate manifest file. + // more info: https://webpack.js.org/guides/code-splitting-libraries/#manifest-file + new webpack.optimize.CommonsChunkPlugin({ + // Check if vendor file exists, if it does, + // generate a seperate chucks for vendor and manifest file + // else don't generate any common chunck + names: checkIfVendorFileExists ? ['vendor', 'manifest'] : [], + }), + // Need this plugin for deterministic hashing + // until this issue is resolved: https://github.com/webpack/webpack/issues/1315 + new WebpackMd5Hash(), // Minify the code. new webpack.optimize.UglifyJsPlugin({ compress: { diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index a304b22d701..a108b97e30a 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -58,6 +58,7 @@ "webpack": "2.5.1", "webpack-dev-server": "2.4.5", "webpack-manifest-plugin": "1.1.0", + "webpack-md5-hash": "0.0.5", "whatwg-fetch": "2.0.3" }, "devDependencies": { From b7a0757dcb3e95282c463dc69beb38390842d9dc Mon Sep 17 00:00:00 2001 From: Shriyans Date: Tue, 23 May 2017 15:38:11 +0900 Subject: [PATCH 3/4] fixed configuration for long term caching in context of the acticle linked in https://github.com/facebookincubator/create-react-app/issues/2328 --- .../config/webpack.config.prod.js | 48 ++++++++++++++----- packages/react-scripts/package.json | 2 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 37a795eb40c..812b0c82f1d 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -14,7 +14,7 @@ const autoprefixer = require('autoprefixer'); const path = require('path'); const fs = require('fs'); const webpack = require('webpack'); -const WebpackMd5Hash = require('webpack-md5-hash'); +const NameAllModulesPlugin = require('name-all-modules-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); @@ -264,6 +264,41 @@ module.exports = { ], }, plugins: [ + // configuration for vendor splitting and long term caching + // more info: https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 + new webpack.NamedModulesPlugin(), + new webpack.NamedChunksPlugin(chunk => { + if (chunk.name) { + return chunk.name; + } + return chunk.modules + .map(m => path.relative(m.context, m.request)) + .join('_'); + }), + new webpack.optimize.CommonsChunkPlugin( + // Check if vendor file exists, if it does, + // generate a seperate chucks for vendor + // else don't generate any common chunck + checkIfVendorFileExists + ? { + name: 'vendor', + minChunks: Infinity, + } + : { names: [] } + ), + // We need to extract out the runtime into a separate manifest file. + // more info: https://webpack.js.org/guides/code-splitting-libraries/#manifest-file + new webpack.optimize.CommonsChunkPlugin( + // Check if vendor file exists, if it does, + // generate a seperate chucks for manifest file + // else don't generate any common chunck + checkIfVendorFileExists + ? { + name: 'manifest', + } + : { names: [] } + ), + new NameAllModulesPlugin(), // Makes some environment variables available in index.html. // The public URL is available as %PUBLIC_URL% in index.html, e.g.: // @@ -292,17 +327,6 @@ module.exports = { // It is absolutely essential that NODE_ENV was set to production here. // Otherwise React will be compiled in the very slow development mode. new webpack.DefinePlugin(env.stringified), - // We need to extract out the runtime into a separate manifest file. - // more info: https://webpack.js.org/guides/code-splitting-libraries/#manifest-file - new webpack.optimize.CommonsChunkPlugin({ - // Check if vendor file exists, if it does, - // generate a seperate chucks for vendor and manifest file - // else don't generate any common chunck - names: checkIfVendorFileExists ? ['vendor', 'manifest'] : [], - }), - // Need this plugin for deterministic hashing - // until this issue is resolved: https://github.com/webpack/webpack/issues/1315 - new WebpackMd5Hash(), // Minify the code. new webpack.optimize.UglifyJsPlugin({ compress: { diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index d1e7b768a51..2878f58d310 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -46,6 +46,7 @@ "fs-extra": "3.0.1", "html-webpack-plugin": "2.28.0", "jest": "20.0.3", + "name-all-modules-plugin": "^1.0.1", "object-assign": "4.1.1", "postcss-flexbugs-fixes": "3.0.0", "postcss-loader": "2.0.5", @@ -58,7 +59,6 @@ "webpack": "2.5.1", "webpack-dev-server": "2.4.5", "webpack-manifest-plugin": "1.1.0", - "webpack-md5-hash": "0.0.5", "whatwg-fetch": "2.0.3" }, "devDependencies": { From 9345cfaf8a35ce76170334e2d116f988b46c552b Mon Sep 17 00:00:00 2001 From: Shriyans Date: Tue, 23 May 2017 17:52:09 +0900 Subject: [PATCH 4/4] added defer attribute to scripts --- packages/react-scripts/config/webpack.config.prod.js | 6 ++++++ packages/react-scripts/package.json | 1 + 2 files changed, 7 insertions(+) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 812b0c82f1d..32231f118ec 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,6 +16,7 @@ const fs = require('fs'); const webpack = require('webpack'); const NameAllModulesPlugin = require('name-all-modules-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); @@ -322,6 +323,11 @@ module.exports = { minifyURLs: true, }, }), + // This ensures that the browser will load the scripts in parallel, + // but execute them in the order they appear in the document. + new ScriptExtHtmlWebpackPlugin({ + defaultAttribute: 'defer', + }), // Makes some environment variables available to the JS code, for example: // if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`. // It is absolutely essential that NODE_ENV was set to production here. diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 2878f58d310..641ce7264ff 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -53,6 +53,7 @@ "promise": "7.1.1", "react-dev-utils": "^1.0.3", "react-error-overlay": "^1.0.3", + "script-ext-html-webpack-plugin": "^1.8.0", "style-loader": "0.17.0", "sw-precache-webpack-plugin": "0.9.1", "url-loader": "0.5.8",