React + Webpack construction and packaging optimization, reactwebpack
This article describes how to optimize React + Webpack construction and packaging. The details are as follows:
Use babel-react-optimize to optimize the React code
Check unused libraries and remove import references
Package the class libraries as needed, such as lodash and echart.
Lodash can be optimized using babel-plugin-lodash.
Note that
Babel-plugin-transform-react-remove-prop-types is used in babel-react-optimize. Under normal circumstances, if you do not reference the PropTypes of the component in the code, it is completely OK. If your component is used, using this plug-in may cause problems.
For details, see:
Https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types#is-it-safe
Webpack build packaging Optimization
Webpack build and package mainly involves the following two problems:
- Slow Webpack Construction
- The size of the Webpack package is too large.
Slow Webpack Construction
You can use Webpack. DDLPlugin and HappyPack to increase the building speed. For more information, see the document of James in DMP DDLPlugin. The original article is as follows:
Webpack. DLLPlugin
Add a webpack. dll. config. js
A DllPlugin plug-in is used to independently package some third-party resources and put them in a manifest. json configuration file,
In this way, after the component is updated, the third-party resources will not be re-built,
- Independently configure the dll/vendors. js file and provide it to webpack. dll. config. js.
- Modify package. json
Add "dll": "webpack -- config webpack. dll. config. js -- progress -- colors" to scripts ",.
After the npm run dll is executed, two file vendor-manifest.json files will be produced under the dll Directory, vendor. dll. js
Configure the webpack. dev. config. js file, add a DllReferencePlugin plug-in, and specify the vendor-manifest.json File
new webpack.DllReferencePlugin({ context: join(__dirname, 'src'), manifest: require('./dll/vendor-manifest.json')})
Modify html
<% if(htmlWebpackPlugin.options.NODE_ENV ==='development'){ %> <script src="dll/vendor.dll.js"></script><% } %>
Note: You must configure the NODE_ENV parameter in the htmlWebpackPlugin plug-in.
Happypack
Improve rebuild efficiency https://github.com/amireh/happypack by multithreading, caching, and other methods
Create multiple happypacks for different resources in webpack. dev. config. js, such as one in js and one in less, and set the id.
new HappyPack({ id: 'js', threadPool: happyThreadPool, cache: true, verbose: true, loaders: ['babel-loader?babelrc&cacheDirectory=true'],}),new HappyPack({ id: 'less', threadPool: happyThreadPool, cache: true, verbose: true, loaders: ['css-loader', 'less-loader'],})
In module. rules, configure use as happypack/loader and Set id
{ test: /\.js$/, use: [ 'happypack/loader?id=js' ], exclude: /node_modules/}, { test: /\.less$/, loader: extractLess.extract({ use: ['happypack/loader?id=less'], fallback: 'style-loader' })}
Reduce the size of the Webpack package file
First, we need to analyze the entire bundle, which is composed of and the size of each component.
Webpack-bundle-analyzer is recommended here. After the installation, add the plug-in webpack. dev. config. js to automatically open the analysis results on the website after each start, as shown in figure
plugins.push( new BundleAnalyzerPlugin());
In addition, the packaging process can be output as a json file.
webpack --profile --json -> stats.json
Then go to the following two websites for analysis
- Webpack/analyze
- Webpack Chart
The preceding graph analysis shows the composition and size of bundle. js.
The solution to bundle. js's bulky size is as follows:
- Enable compression and Other plug-ins in the production environment to remove unnecessary plug-ins
- Split Business Code with third-party libraries and public modules
- Enable gzip compression for webpack
- Load as needed
Enable compression and Other plug-ins in the production environment to remove unnecessary plug-ins
Make sure to start webpack. DefinePlugin and webpack. optimize. UglifyJsPlugin in the production environment.
const plugins = [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production') }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, drop_console: false //eslint-disable-line } }) ]
Split Business Code with third-party libraries and public modules
Because the Business Code of the Project changes frequently, the code changes of third-party libraries are less frequently. If you package the Business Code and the third database to the same chunk, even if the Business Code is changed to only one line during each build, even if the code of the third-party database is not changed, the hash of the entire chunk is different from the previous one. This is not the expected result. What we want is that if the code of the third-party library does not change, we should also ensure that the corresponding hash does not change during the construction so that the browser cache can be used, it can improve page loading performance and shorten page loading time.
Therefore, the code of the third database can be separately split into the vendor chunk, which is separated from the Business Code. In this way, even if the Business Code changes, as long as the third-party library code does not change, the corresponding hash will not change.
First, configure two chunks for the entry app and for the vendor app.
entry: { vendor: [path.join(__dirname, 'dll', 'vendors.js')], app: [path.join(__dirname, 'src/index')]},output: { path: path.resolve(__dirname, 'build'), filename: '[name].[chunkhash:8].js'},
Among them, vendros. js is a custom third-party library that needs to be included in the vendor, as follows:
require('babel-polyfill');require('classnames');require('intl');require('isomorphic-fetch');require('react');require('react-dom');require('immutable');require('redux');
Then split the third library through CommonsChunkPlugin
Plugins. push (// split the third-party library new webpack. optimize. commonsChunkPlugin ({name: 'vendor'}), // split the webpack code into new webpack. optimize. commonsChunkPlugin ({name: 'runtime', minChunks: Infinity }));
The configuration above has two details to note:
- Use chunkhash instead of hash
- Separate split webpack code
Use chunkhash instead of hash
Let's take a look at the differences between the two:
- Hash is build-specific. Any changes to a file may lead to different compilation results. It is applicable to the development stage.
- Chunkhash is a chunk-specific hash calculated based on the content of each chunk and is suitable for production.
Therefore, in order to ensure that the hash of the corresponding vendor. js Library remains unchanged, chunkhash is used in output. filename.
Separate split webpack code
Webpack has a known problem:
The boilerplate and manifest codes of webpack may change at each compilation.
As a result, we only changed a line of code in the entry file, but both the compiled vendor and entry chunk have changed because they all contain this part of code.
This is unreasonable, because in fact the code of our third-party library has not changed, and vendor should not change when our business code changes.
Therefore, we need to separate the webpack code.
new webpack.optimize.CommonsChunkPlugin({ name: "runtime", minChunks: Infinity}),
If the name is not an entry, "runtime" or "manifest" is usually used ".
The minChunks parameter indicates the minimum number of chunks that need to be included before the public chunk (commons chunk) is passed in. If the number must be greater than or equal to 2 or less than the number of chunks, the public chunk will be generated immediately after Infinity is passed in, but there is no module in it.