Webpack 优化与 DLL
分析包内容
bash
yarn add -D webpack-bundle-analyzeryarn add -D webpack-bundle-analyzerjs
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
plugins: [new BundleAnalyzerPlugin()],
}const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
plugins: [new BundleAnalyzerPlugin()],
}noParse
不去解析某个包(如 jquery 没有引用其他模块),减少解析时间:
js
module: {
noParse: /jquery/,
}module: {
noParse: /jquery/,
}exclude & include
js
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve('src'),
},
],
}module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: path.resolve('src'),
},
],
}IgnorePlugin(忽略不必要的引入)
忽略包内部引入的所有文件,如 moment 会默认加载所有 locale 文件:
js
const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.IgnorePlugin(/\.\/locale/, /moment/),
],
}
// 需要时手动引入所需语言包:
// import 'moment/locale/zh-cn'const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.IgnorePlugin(/\.\/locale/, /moment/),
],
}
// 需要时手动引入所需语言包:
// import 'moment/locale/zh-cn'DllPlugin(动态链接库)
将不常变动的第三方库(react、axios 等)提前打包,减少每次构建时间。
1. 创建 dll 打包配置 webpack.dll.js
js
const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
react: ['react', 'react-dom'],
others: ['axios', 'js-cookie'],
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]',
},
plugins: [
new CleanWebpackPlugin(),
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.resolve(__dirname, 'dist', 'manifest.json'),
}),
],
}const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
mode: 'development',
entry: {
react: ['react', 'react-dom'],
others: ['axios', 'js-cookie'],
},
output: {
filename: '_dll_[name].js',
path: path.resolve(__dirname, 'dist'),
library: '_dll_[name]',
},
plugins: [
new CleanWebpackPlugin(),
new webpack.DllPlugin({
name: '_dll_[name]',
path: path.resolve(__dirname, 'dist', 'manifest.json'),
}),
],
}运行 npx webpack --config webpack.dll.js 打包一次,然后在 HTML 中引入:
html
<script src="/_dll_react.js"></script><script src="/_dll_react.js"></script>2. 修改主配置引用
js
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json'),
}),
],
}module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json'),
}),
],
}HappyPack(多线程打包)
项目较大时使用,小项目反而更慢:
bash
yarn add happypackyarn add happypackjs
const Happypack = require('happypack')
module.exports = {
module: {
rules: [
{ test: /\.js$/, use: 'Happypack/loader?id=js' },
],
},
plugins: [
new Happypack({
id: 'js',
use: [
{ loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } },
],
}),
],
}const Happypack = require('happypack')
module.exports = {
module: {
rules: [
{ test: /\.js$/, use: 'Happypack/loader?id=js' },
],
},
plugins: [
new Happypack({
id: 'js',
use: [
{ loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } },
],
}),
],
}Tree Shaking(摇晃树)
在生产环境下,import 引入的代码会自动去除没用的代码(即 tree-shaking)。
Scope Hoisting(作用域提升)
Webpack 3+ 自动简化代码,将声明过于简洁的变量(如单个数字)直接省略。
TerserPlugin(压缩 JS)
bash
npm i terser-webpack-plugin -Dnpm i terser-webpack-plugin -Djs
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
format: { comments: false },
compress: { drop_console: true },
},
extractComments: false,
}),
],
},
}const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
format: { comments: false },
compress: { drop_console: true },
},
extractComments: false,
}),
],
},
}CssMinimizerPlugin(优化 CSS)
bash
npm i css-minimizer-webpack-plugin -Dnpm i css-minimizer-webpack-plugin -Djs
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin({
minimizerOptions: {
preset: ['advanced', { zindex: false }],
},
}),
],
},
}const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin({
minimizerOptions: {
preset: ['advanced', { zindex: false }],
},
}),
],
},
}CSS 压缩与 JS 优化配合
js
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true }),
new OptimizeCssAssetsPlugin({}),
],
},
}const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new UglifyJsPlugin({ cache: true, parallel: true, sourceMap: true }),
new OptimizeCssAssetsPlugin({}),
],
},
}用了 CSS 优化,必须同时优化 JS,否则 JS 不会压缩成一行。
SplitChunks(抽离公共模块)
当多个入口文件引入了相同模块时,抽离出来只打包一份:
js
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
common: {
chunks: 'initial',
minSize: 0,
minChunks: 2, // 引用两次即抽离
},
vendor: {
priority: 1,
test: /node_modules/,
chunks: 'initial',
minSize: 0,
minChunks: 2,
},
},
},
},
}module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
common: {
chunks: 'initial',
minSize: 0,
minChunks: 2, // 引用两次即抽离
},
vendor: {
priority: 1,
test: /node_modules/,
chunks: 'initial',
minSize: 0,
minChunks: 2,
},
},
},
},
}懒加载
使用 webpack 内置的 import() 语法,返回 Promise:
js
const btn = document.createElement('button')
btn.addEventListener('click', function () {
import('./a.js').then((data) => {
console.log(data.default)
})
})const btn = document.createElement('button')
btn.addEventListener('click', function () {
import('./a.js').then((data) => {
console.log(data.default)
})
})如需兼容:
bash
yarn add @babel/plugin-syntax-dynamic-import -Dyarn add @babel/plugin-syntax-dynamic-import -Djs
options: { plugins: ['@babel/plugin-syntax-dynamic-import'] }options: { plugins: ['@babel/plugin-syntax-dynamic-import'] }
Cao Note