brief introduction
Read "Shallow web pack" to summarize common web pack construction optimization strategies, you can improve the speed of project construction by the following means
More precise loader rules
Write the loader rules clearly
Just let the files that need to be processed go into the loader process as follows
rules: [{ // Regular as accurate as possible test: /\.js$/, // With caching, it compiles faster when the file is unchanged after caching (see Supplement 1 for cache lookup principles) use: ['babel-loader?cacheDirectory'], // Specify directories to process include: path.resolve(__dirname, 'src') // In theory, only include is sufficient, but in some cases you can use this to exclude files that do not need to be processed // exclude: [] }]
Find directories more accurately
Set Find Path to Precise
Theoretically, the third-party dependencies of our projects should all be under the node_modules of our own projects, so we can set the lookup directory to reduce the default lookup of nodes (see Supplement 2 for the default lookup method)
module.exports = { resolve: { // Specify the node_modules directory under the current directory modules: [path.resolve(__dirname, 'node_modules')] } }
More precise extensions
Try to put more types of files first
Writing code in general, we are used to writing file names directly instead of extensions, so parsing is done according to the following properties
module.exports = { extensions: ['.js', '.jsx', '.ts', '.tsx'], }
Default value
extensions: [".js", ".json"]
Pre-compile large modules using dynamic link libraries
Compile large modules ahead of time using dynamic link libraries
See Supplement 3 for principles
Create a new file, webpack_dll.config.js, as follows
const path = require('path'); const webpack = require('webpack'); // Place the reused large modules here so that you don't need to recompile them every time const vendors = [ 'react', 'react-dom', 'lodash' ]; module.exports = { mode: 'development', output: { path: path.resolve(__dirname, './dist'), filename: '[name].js', library: '[name]', }, entry: { vendors, }, plugins: [ new webpack.DllPlugin({ path: path.resolve(__dirname, './dist/manifest.json'), name: '[name]', }), ], };
Execute webpack --config webpack_dll.config.js for the first compilation (if a newer version needs to be compiled again)
Then introduce manifest.json into your webpack configuration file
plugins: [ new webpack.DllReferencePlugin({ manifest: require('./dist/manifest.json') }) ],
Multiprocessing Files
Using HappyPack to handle multiple loader compilation tasks simultaneously
To function as a multi-core CPU computer, use HappyPack to distribute tasks to multiple sub-processes and execute them concurrently
const path = require('path'); const HappyPack = require('happypack'); // Share 5 process pools const happyThreadPool = HappyPack.ThreadPool({ size: 5 }); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist'), }, module: { // noParse: [/react\.production\.min\.js$/], rules: [{ test: /\.js$/, // And the following plugin id until happypack finds it use: ['happypack/loader?id=babel'], include: path.resolve(__dirname, 'src') }] }, plugins: [ // Plugins can instantiate multiple new HappyPack({ // Corresponds to above id: 'babel', // The actual loader to use loaders: ['babel-loader?cacheDirectory'], // Default number of open processes threads: 3, // Allow happyPack to print logs verbose: true, // Number of shared processes, if you use more than one happyplugin, the official recommendation is to share the process pool threadPool: happyThreadPool }) ], };
Principle See Supplement 4
Multiprocess Compressed File
Compress files simultaneously using ParallelUglifyPlugin multi-process
ParallelUglifyPlugin
YesUglifyJS
On the basis of this, the capacity of multi-input and multi-output processing is added to speed up the compression speedimport ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin'; module.exports = { plugins: [ new ParallelUglifyPlugin({ test, include, exclude, cacheDir, workerCount, sourceMap, uglifyJS: { }, uglifyES: { } }), ], };
Reduce listening files
Reduce listening files
Principle See Supplement 5
When we use the watch ability of webpack for file listening, a better way is to control the listening directory, as follows, excluding node_modules reduces listening on that directory, reduces compiling files that need to be looped, and improves checking speed
module.export = { watchOptions: { ignored: /node_modules/ } }
Other less important optimizations
More accurate mainFields
The default way to find this value is on the official website Click here
Looking at react and lodash, there's only one main, and es6 doesn't seem to be common at the moment, so this value may not be important right now
module.exports = { resolve: { mainFields: ['main'] } }
Third-party library mapping
Why is this unimportant? I find that index.js exported directly from react determines which code to use based on the environment, and visually does not require cyclical dependency processing
Dependencies allow you to use packaged code directly instead of Web packs to de-cycle dependencies
resolve: { mainFields: ["main"], alias: { 'react': path.resolve(__dirname, './node_modules/react/cjs/react.production.min.js') } }
devServer without inline mode
Principle See Supplement 6
By default, the application enables inline mode.This means that a script that handles real-time overloading is inserted into your bundle and the build message will appear in the browser console.
When using inline mode, devServer injects an overloaded piece of script code into each Chunk, but it only needs one page, so if there are too many Chunks, inline can be set to false
module.export = { devServer: { inline: false } }
supplement
Supplementary 1-cacheDirectory Principle
When the cache directory is set, the specified directory will be used to cache the results of the loader's execution.Subsequent webpack builds will attempt to read the cache to avoid the high-performance, potentially expensive Babel recompiling process that can occur at each execution.If a null value (loader:'babel-loader? cacheDirectory') or true (loader: babel-loader?cacheDirectory=true) is set, the loader will use the default cache directory node_modules/.cache/babel-loader, and if the node_modules directory is not found in any root directory, the downgrade will fall back to the default temporary file directory of the operating system.
Supplement default 2-node lookup
- Find the node_modules directory in the current directory to see if there is a match, and if so, hit the file
- Find the node_modules under the parent directory, if any, hit the file
- Follow this rule and search all the way to the parent directory until you reach the node_modules under the root directory
Supplementary 3-Dynamic Link Library Ideas
Modules that can be reused in a large number of projects only need to be compiled once, and modules contained in a passive dynamic link library will not be recompiled during subsequent builds, but will use the code in the dynamic link library directly.(Note: If you upgrade a dependent module version, you will need to recompile the dynamic link library)
Supplementary 4-HappyPack Principle
In the construction of webpack, a large number of loader conversion operations are required, which is time consuming. Because nodejs are single-threaded, if you want to make better use of the multi-core capabilities of the cpu, you can start multiple processes and process the files at the same time. You can see that in the configuration file, we give the files to happypack-loader to process each time, and happypack to schedule the processing of the files (happypack)Which loaders to use for processing is known by id)
Supplement 5-File Listening Principles
The webpack triggers from the entry, puts all the dependencies into a list, modifies the contents of the file each time, goes back and traverses the entire list to see if there is a change in editing time, and compiles if there is one
Supplement 6-Automatic Refresh Principle
- Inject proxy client code into the page to be developed and refresh the entire page through the proxy client (default)
- Put the web page you want to develop into an iframe and refresh it to see the refresh effect