webpack optimization

webpack optimization

As one of the most popular front-end construction tools, webpack has always been criticized for being too high a threshold, and there is no universal configuration suitable for all projects. For this reason, we have to be happy (big mistake: smiley:) manual Configure our project and start our configuration engineer. This article mainly explains some basic configuration of webpack and some optimization work we can do. It is suitable for front-end developers who have used webpack to read. You may wish to read it during the reading process. Open your own project to optimize with me.
Split configuration file dev prod Usually our project will have a development environment and a production environment, and the goal of the development environment we configure is to build faster, module hot replacement, and error information corresponding to the source map from the chrome console (source map) Wait. In the production environment, we pay more attention to optimization points such as chunk separation, caching, security, and tree shaking. Of course, the configuration files for the development and production environments are definitely not the same, so we separate the configuration files for different environments, and extract the common parts at the same time, and finally use the webpack-merge plugin to integrate.
[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
11
//
const webpackMerge = require('webpack-merge');
const additionalConfigPath = {
development: './webpack.dev.config.js',
production: './webpack.prod.config.js'
};
const baseConfig = {};
module.exports = webpackMerge(
baseConfig,
require(additionalConfigPath[process.env.NODE_ENV])
);

In the optimization points below, I will mark the environment where these points are applicable dev=development environment prod=production environment

Code separation prod code separation can separate the project code into various files, and then load or load these files in parallel. It is also used to obtain smaller bundles and control the priority of resource loading.
There are three common code separation methods for webpack:
  • Entry starting point: Configure multiple entries and output multiple chunks.
  • Prevent duplication: Use CommonsChunkPlugin to remove duplicates and separate chunks (Although webpack4 is obsolete, there are alternative methods)
  • Dynamic import: often used to separate modules loaded on demand


[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
11
12
// chunk
module.exports = {
entry: {
index: 'index.js',
module: 'module.js'
},
output: {
//[name]
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};



The problem is: if there are duplicate modules in the entry chunks, such as jquery, those duplicate modules will be introduced into each bundle

remove duplicates
For webpack4 <4 we use CommonsChunkPlugin plugin
[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
entry: {
"app": "entry-client.js"
}
//app
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
filename: '[name].[chunkHash:6].common.js',
chunks: ['app']
})
// vendor runtime
new webpack.optimize.CommonsChunkPlugin({
name: ['vendor','runtime'],
filename: '[name].[chunkHash:6].bundle.js',
// vendor chunk
minChunks: Infinity
}),
The chunks option represents the entrance from which to separate public files. Here we use the main entrance app of our project to separate custom public modules
1. separate the custom public modules separately. The purpose of this is to facilitate our caching. When the custom module is updated, the hash value of the vendor file will not be affected.
Then separate the third-party library files and webpack running files.
In this way, our vendor is very clean. It only contains third-party libraries and can be used for long-term caching. This place needs to separate the webpack running file runtime, because no matter whether we modify the project file or not, the hash value of the runtime file will always change every time the project is built, and it needs to be typed out separately.
For webpack4 we need to achieve the same goal

[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
//
optimization: {
splitChunks: {
chunks: "all",
minSize: 20000,
//chunk
minChunks: 1,
//name + hash
name: true,
//
cacheGroups: {
//
commons: {
name: 'common',
//
priority: 10,
//chunk
chunks: 'initial'
},
//
vendors: {
//
test:/[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
},
}
}
}
//webpack
runtimeChunk: {
name: 'manifest'
},


require.ensure now depends on the native Promise. If you use require.ensure in an environment that does not support Promise, you need to add a polyfill.
Asynchronous loading of ordinary components Since we can use import() and require.ensure to dynamically import components, in fact, we can achieve component-based asynchronous loading in the project.
For example, our homepage is composed of 20 components, but only 15 components are displayed on the first screen. The other 5 components may be some pop-up windows, or the components displayed at the bottom, then we can use them to import dynamically. Pull it out and load it when needed, such as:


[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
//
<div onClick={this.showPopUps}>
show-popUps
</div>
showPopUps = () => {
this.popUps = ()=> {
import(/*webpackChunkName: 'PopUps'*/'./popUps')
}
}

The problem with this approach is that there will be a certain delay when we click the button to pop up the floating layer, because we only get the components from the server when we click, and the user experience may not be good.
At this time, we can use prefetch, a predictive loading technology. Prefetch reminds the browser that this resource may be needed in the future, and the browser will choose == idle time== to download this resource. Prefetch is often used to speed up the next operation.
<link rel="prefetch">
Compatibility issues: From the above, it can be known that prefetch is implemented based on browsers, and there are certain compatibility issues that have not yet been supported on safari.
It will not affect the functionality of our page in unsupported browsers
Use: preload-webpack-plugin Use conditions: webpack> 2.2 and need to use html-webpack-plugin

[JavaScript]
Plain text view
Copy code
01
02
03
04
05
06
07
08
09
10
11
12
plugins: [
new HtmlWebpackPlugin(),
new PreloadWebpackPlugin({
rel: "prefetch",
as: 'script',
//chunk, "asyncChunks"
include: 'asyncChunks'
})
]
//
<link rel="prefetch" as="script" href="chunk.d15e.js">

For files ending in .css as=style, files ending in .woff2 as=font, otherwise as=script, of course you can give a certain value as above.
For the value of include, we don't actually need all asynchronous chunks to use prefetch, so we need to reset the value of include, like this:


[JavaScript]
Plain text view
Copy code
1
2
3
4
5
6
7
//1 prefetch (chunkName)
include: ["PopUps","Login"]
//2 Prefetch
this.popUps = () => {
import(/* webpackChunkName: 'PopUps', webpackPrefetch: true */'./PopUps')
}

Quoted from juejin.im/post/684490...