This article mainly records the next webpack
performance optimization
status quo
As the project continues to develop and grow, the number of components begins to increase, the project also begins to grow, and the webpack
compilation time will be longer and longer. Our current project is compiled only once 40s ——70s
, which is very inefficient. operating. There are many optimization methods. The previous project has already done a lot. This article will explain the optimization from the perspective of caching.
The following only introduces several caching-related optimization methods, including
-
babel-loader
ofcacheDirectory
-
cache-loader
-
dll
Dynamic link library -
HardSourceWebpackPlugin
Let me talk about the conclusion first, the first one is the existing one in the project, the second and the third have little effect, and the fourth one has achieved the expected effect.
Our webpack version: 4.41.2, system: mac os
Bottleneck analysis
The first step of optimization should be to analyze the current performance, here we use the speed-measure-webpack-plugin
speed analysis
// 安装
npm install --save-dev speed-measure-webpack-plugin
// 使用方式
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const webpackConfig = smp.wrap({
plugins: [
new MyPlugin(),
new MyOtherPlugin()
]
});
The results are similar to the following, you can see the time-consuming of each Loader
and every one Plugin
, with this, we can "prescribe the right medicine"
But it should be noted that: HardSourceWebpackPlugin and speed-measure-webpack-plugin cannot be used together , which makes me depressed for a long time
babel-loader 的 cacheDirectory
babel-loader
It is allowed to use Babel
and webpack
translate JavaScript
files. Sometimes if we run babel-loader
very slowly, we can consider ensuring that as few files as possible are translated. You may use /\.m?js$/
to match, which may translate node_modules
directories or other unneeded source code, resulting in performance degradation
You can exclude
exclude some files that do not need to be compiled. For example, the following will not escape node_modules
and bower_components
the contents of the folder
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-proposal-object-rest-spread']
}
}
}
]
}
You can also speed up at least twice by using cacheDirectory
options babel-loader
. This will cache the result of the translation in the file system. cacheDirectory
The default value is false
. When set, the specified directory will be used to cache loader
the execution results. In subsequent webpack
constructions, it will try to read the cache to avoid the high-performance consumption Babel
recompilation process that may occur each time it is executed ( recompilation process
). If an empty value is set (loader: 'babel-loader?cacheDirectory')
or true (loader: 'babel-loader?cacheDirectory=true')
, the loader will use the default cache directory node_modules/.cache/babel-loader
. If no directory is found in any root node_modules
directory, it will downgrade and fall back to the default temporary file directory of the operating system.
{
test: /\.js$/,
use: 'babel-loader?cacheDirectory',
include: [resolve('src'), resolve('test') ,resolve('node_modules/webpack-dev-server/client')]
}
cache-loader
Except babel-loader
, if we want to loader
cache other processing results, what should we do?
The answer is that it can be used cache-loader
. loader
Add before some high performance overhead cache-loader
, in order to cache the results to disk
installation
npm install --save-dev cache-loader
Configuration
module.exports = {
module: {
rules: [
{
test: /\.ext$/,
use: ['cache-loader', ...loaders],
include: path.resolve('src'),
},
],
},
};
⚠️ Please note that saving and reading these cache files will have some time overhead, so please use this loader only for loader with high performance overhead
In addition to the default configuration, cache-loader
some other options are provided, see cache-loader[1] for details
dll caching scheme
What is a DLL?
The DLL file is a dynamic link library, and a dynamic link library can contain functions and data called for other modules
Why use DLL?
The reason is that the dynamic link library containing a large number of reused modules only needs to be compiled once, and the modules contained in the dynamic link library will not be recompiled in the subsequent construction process, but directly use the code in the dynamic link library. Since most of the dynamic link library contains commonly used third-party modules, for example Vue react、react-dom
, as long as the version of these modules is not upgraded, the dynamic link library does not need to be recompiled
how to use?
To complete the following three steps:
-
Pull away. Extract the basic modules that the web page depends on and pack them into separate dynamic link libraries. A dynamic link library can contain multiple modules
-
Obtain. When the module that needs to be imported exists in a dynamic link library, this module cannot be packaged again, but is obtained from the dynamic link library
-
load. All dynamic link libraries that the page depends on need to be loaded
Used DllPlugin
and DllReferencePlugin
completed before , but its configuration is very complicated, and if the file is updated, the dll needs to be regenerated manually. AutoDllPlugin[2] is selected here, it will automatically complete the functions of the above two plug-ins, this is Vue-cli
a plug-in that has been used
installation:
webpack 4
npm install --save-dev autodll-webpack-plugin
webpack 2 / 3
npm install --save-dev [email protected]
Basic use:
plugins: [
new HtmlWebpackPlugin({
inject: true,
template: './src/index.html',
}),
new AutoDllPlugin({
inject: true, // will inject the DLL bundles to index.html
filename: '[name].js',
entry: {
vendor: [
'react',
'react-dom'
]
}
})
]
Before optimization
Optimized
Compiling for the first time:
Second compilation:
Optimized for a few seconds, but little effect
The result is not very effective, because webpack4
the performance is good enough, Vue-cli
and this function is also abolished.
HardSourceWebpackPlugin
installation:
npm install --save-dev hard-source-webpack-plugin
# or
yarn add --dev hard-source-webpack-plugin
Configuration:
// webpack.config.js
var HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
context: // ...
entry: // ...
output: // ...
plugins: [
new HardSourceWebpackPlugin()
]
}
Before optimization
As you can see, it takes 50s
Optimized
First start
Second start
It only takes 7 s, which is reduced 43 s
, and the speed is increased by about 80%. The purpose of optimization is achieved!
Hot update speed
Seeing issue
that it mentioned about hot update, it will be slower, I used our project to do some tests, the following is the test data
Before optimization
js: 2443ms 1634ms 1844ms 2532ms 1443ms 1248ms
html: 1094ms 1232ms 1119ms 1490ms 1264ms
css: 1422ms 1186ms 1341ms 1562ms 1183ms
Optimized
js: 2429ms 2436ms 2860ms 2528ms 1917ms 1487ms 1450ms 1450ms 1557ms 2198ms
html: 2855ms 1569ms 1400ms 1298ms 1204ms 1299ms 1578ms 1485ms 2028ms
css: 2035ms 1406ms 1415ms 1600ms 1773ms 1604ms
In comparison, sometimes it is a bit slower, but overall it is acceptable. But there are also some impacts, so two npm script
commands have been added to the project . If you don’t want to open it, you can directly npm run dev:noCache
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=true",
"dev:noCache": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js --cache=false"
}
In build/webpack.dev.conf.js
the
if (args.cache) {
devConfig = merge(devConfig, {
plugins: [new HardSourceWebpackPlugin()]
})
}
emphasize again:
HardSourceWebpackPlugin and speed-measure-webpack-plugin cannot be used together
Looking to the future
webpack 5
Has been released, which has a very attractive feature-persistent cache (it is said that the thinking HardSourceWebpackPlugin
is the same)
By cache
caching the generated webpack
modules and chunk
to improve the build speed. cache
Will be set to in development mode type: 'memory'
and disabled in production mode
module.exports = {
cache: {
// 1. 将缓存类型设置为文件系统
type: 'filesystem',
buildDependencies: {
// 2. 将你的 config 添加为 buildDependency,以便在改变 config 时获得缓存无效
config: [__filename],
// 3. 如果你有其他的东西被构建依赖,你可以在这里添加它们
// 注意,webpack、加载器和所有从你的配置中引用的模块都会被自动添加
},
},
};