下载资源文件、相关配置 # 优化
效率分析工具
安装以下 webpack 插件,可以帮助我们分析优化效率:
progress-bar-webpack-plugin
:查看编译进度
speed-measure-webpack-plugin
:查看编译速度
webpack-bundle-analyzer
:打包体积分析
安装:
yarn add -D progress-bar-webpack-pluginyarn add -D speed-measure-webpack-pluginyarn add -D webpack-bundle-analyzer
编译进度条
webpack.common.js 配置方式如下:
const chalk = require('chalk')const ProgressBarPlugin = require('progress-bar-webpack-plugin')module.exports = { plugins: [ // 进度条 new ProgressBarPlugin({ format: ` :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)` }) ],}
编译速度分析
webpack.dev.js 配置方式如下:
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");const smp = new SpeedMeasurePlugin();module.exports = smp.wrap({ // ...webpack config...})
打包体积分析
使用
webpack-bundle-analyzer
查看打包后生成的 bundle 体积
分析,将 bundle 内容
展示为一个便捷的、交互式、可缩放的树状图形
式。帮助我们分析输出结果来检查模块在何处结束。 webpack.prod.js 配置方式如下:const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");module.exports = { plugins: [ // 打包体积分析 new BundleAnalyzerPlugin() ],}
package.json中修改启动命令
"analyzer": "cross-env NODE_ENV=production webpack --progress --mode production"
执行编译命令 npm run analyzer,打包结束后自行启动地址为
http://127.0.0.1:8888
开发环境优化
热更新
webpack-dev-server
使用 webpack 内置的 HMR 插件,更新
webpack-dev-server
配置。webpack.dev.js 配置方式如下:
module.export = { devServer: { static: './dist', hot: true, // 热更新 },}
react-refresh-webpack-plugin
使用
react-refresh-webpack-plugin
热更新 react 组件。安装:
yarn add -D @pmmmwh/react-refresh-webpack-plugin react-refresh
webpack.dev.js 配置方式如下:
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');module.exports = { plugins: [ new webpack.HotModuleReplacementPlugin(), new ReactRefreshWebpackPlugin(), ]}
Source Map
eval-cheap-module-source-map
- 本地开发首次打包慢点没关系,因为 eval 缓存的原因,rebuild 会很快
- 开发中,我们每行代码不会写的太长,只需要定位到行就行,所以加上 cheap
- 我们希望能够找到源代码的错误,而不是打包后的,所以需要加上 module
加快构建速度
缓存
cache持久化缓存
通过配置 cache 缓存生成的 webpack 模块和 chunk,来改善构建速度。
webpack.common.js 配置方式如下:
module.exports = { cache: { type: 'filesystem', // 使用文件缓存 },}
优化loader、plugins的配置
减少 loader 配置数量
每个的 loader、plugin 都有其启动时间。尽量少地使用工具,将非必须的 loader、plugins 删除。
使用 webpack 资源模块 (asset module) 代替旧的 assets loader 使用 webpack cache 代替 cache-loader、dll、hard-source-webpack-plugin
file-loader
url-loader
raw-loader
cache-loader
(缓存一些性能开销比较大的 loader 的处理结果)
autodll-webpack-plugin
hard-source-webpack-plugin
(为模块提供了中间缓存,重复构建时间大约可以减少 80%)
为loader指定 include/exclude
为
loader
指定 include,减少 loader
应用范围,仅应用于最少数量的必要模块。include
:符合条件的模块进行解析
exclude
:排除符合条件的模块,不解析,exclude
优先级更高
如:
{ test: /\.css$/, include: paths.appSrc, use: [ // 将 JS 字符串生成为 style 节点 "style-loader", // 将 CSS 转化成 CommonJS 模块 "css-loader", ],},
缩小webpack解析的范围
优化resolve配置
resolve
用来配置 webpack 如何解析模块,可通过优化 resolve
配置来覆盖默认配置项,减少解析范围:alias
extensions
- 高频文件后缀名放前面
- 手动配置后,默认配置会被覆盖,可以用 … 扩展运算符代表默认配置
modules
- 告诉 webpack 优先 src 目录下查找需要解析的文件,会大大节省查找时间
symlinks
- 如果项目不使用
symlinks
(例如 npm link 或者 yarn link),可以设置resolve.symlinks: false
,减少解析工作量。(npm包开发调试用)
webpack.common.js 配置方式如下:
module.exports = { resolve: { alias: { '@': paths.appSrc, // @ 代表 src 路径 }, extensions: ['.tsx', '.ts', '.js', '...'], modules: ['node_modules', paths.appSrc], symlinks: false, }}
使用externals配置
externals
配置选项提供了「从输出的 bundle 中排除依赖」
的方法,我们可以用这样的方法来剥离不需要改动的一些依赖,大大节省打包构建的时间。例如,从 CDN 引入 jQuery,而不是把它打包:
<script src="https://code.jquery.com/jquery-3.1.0.js" integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk=" crossorigin="anonymous"></script>
webpack.common.js 配置方式如下:
module.exports = { externals: { jquery: 'jQuery', },}
使用jQuery
import $ from 'jquery';$('.element').animate(/* ... */);
多线程编译构建
通过
thread-loader
将耗时的 loader
放在一个独立的 worker 池中运行,加快 loader
构建速度。安装:
yarn add -D thread-loader
使用时,需将此
loader
放置在其他 loader
之前,应该仅在非常耗时的 loader
前引入 thread-loader
,在项目中sass-loader
转换时间较长,webpack.common.js 配置方式如下:module.exports = { rules: [ { test: /\.module\.(scss|sass)$/, include: paths.appSrc, use: [ 'style-loader', { loader: 'css-loader', options: { modules: true, importLoaders: 2, }, }, { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ [ 'postcss-preset-env', ], ], }, }, }, { loader: 'thread-loader', options: { workerParallelJobs: 2 } }, 'sass-loader', ].filter(Boolean), }, ]}
打包结果优化(体积)
CssMinimizerWebpackPlugin
/optimize-css-assets-webpack-plugin
TerserWebpackPlugin
(webpack5自带)
SplitChunksPlugin
(webpack5自带)
MiniCssExtractPlugin
安装:
yarn add -D css-minimizer-webpack-pluginyarn add -D mini-css-extract-plugin
代码压缩
CSS压缩
CssMinimizerWebpackPlugin
将在 Webpack 构建期间搜索 CSS 文件,优化、压缩 CSS。webpack.prod.js 配置方式如下:
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");module.exports = { optimization: { minimizer: [ new CssMinimizerPlugin({ parallel: 4, }), ], }}
JS压缩
webpack5 自带最新的
terser-webpack-plugin
,无需手动安装。 terser-webpack-plugin
默认开启了 parallel: true
配置,并发运行
的默认数量: os.cpus().length - 1
,这里配置的 parallel
数量为 4,使用多进程并发运行压缩以提高构建速度在生成环境下打包默认会开启 js 压缩,但是当我们手动配置 optimization 选项之后,就不再默认对 js 进行压缩,需要我们手动去配置。
webpack.prod.js 配置方式如下:
const TerserPlugin = require('terser-webpack-plugin');module.exports = { optimization: { minimize: true, // 开启最小化 minimizer: [ new TerserPlugin({ parallel: 4, terserOptions: { parse: { ecma: 8, }, compress: { ecma: 5, warnings: false, comparisons: false, inline: 2, }, mangle: { safari10: true, }, output: { ecma: 5, comments: false, ascii_only: true, }, }, }), ] }}
代码分离
代码分离能够把代码分离到不同的 bundle 中,然后可以按需加载或并行加载这些文件。代码分离可以用于获取更小的 bundle,以及控制资源加载优先级,可以缩短页面加载时间。
抽离重复代码
SplitChunksPlugin
插件开箱即用,可以将公共的依赖模块提取到已有的入口 chunk 中,或者提取到一个新生成的 chunk。webpack 将根据以下条件自动拆分 chunks:
- 新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹;
- 新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积);
- 当按需加载 chunks 时,并行请求的最大数量小于或等于 30;
- 当加载初始化页面时,并发请求的最大数量小于或等于 30;
通过
splitChunks
把react 等公共库
抽离出来,不重复引入占用体积。webpack.prod.js 配置方式如下:
module.exports = { optimization: { minimize: true, // 开启最小化 minimizer: [ new TerserPlugin({ parallel: 4, terserOptions: { parse: { ecma: 8, }, compress: { ecma: 5, warnings: false, comparisons: false, inline: 2, }, mangle: { safari10: true, }, output: { ecma: 5, comments: false, ascii_only: true, }, }, }), ], splitChunks: { // include all types of chunks chunks: 'all', // 重复打包问题 cacheGroups:{ vendors:{ // node_modules里的代码 test: /[\\/]node_modules[\\/]/, chunks: "all", // name: 'vendors', 一定不要定义固定的name priority: 10, // 优先级 enforce: true } } }, }}
CSS分离
MiniCssExtractPlugin
插件将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。webpack.common.js 配置方式如下:
const MiniCssExtractPlugin = require("mini-css-extract-plugin");module.exports = { plugins: [new MiniCssExtractPlugin()], module: { rules: [ { test: /\.module\.(scss|sass)$/, include: paths.appSrc, use: [ 'style-loader', isEnvProduction && MiniCssExtractPlugin.loader, // 仅生产环境 { loader: 'css-loader', options: { modules: true, importLoaders: 2, }, }, { loader: 'postcss-loader', options: { postcssOptions: { plugins: [ [ 'postcss-preset-env', ], ], }, }, }, { loader: 'thread-loader', options: { workerParallelJobs: 2 } }, 'sass-loader', ].filter(Boolean), }, ] },};
Tree Shaking
Tree-shaking 作用是剔除没有使用的代码,以降低包的体积
JS
JS Tree Shaking 将 JavaScript 上下文中的未引用代码(Dead Code)移除。目前在设置mode为production的时候已经自动开启了tree-shaking。但是要想使其生效,生成的代码必须是
ES模块
。不能使用其它类型的模块如CommonJS之类。Dead Code 一般具有以下几个特征:
- 代码不会被执行,不可到达;
- 代码执行的结果不会被用到;
- 代码只会影响死变量(只写不读)。
CSS
CSS 代码也需要摇树,打包时把没有用的 CSS 代码摇走,可以大幅减少打包后的 CSS 文件大小。
使用
purgecss-webpack-plugin
对 CSS Tree Shaking。安装:
yarn add purgecss-webpack-plugin -D
因为打包时 CSS 默认放在 JS 文件内,因此要结合
webpack
分离 CSS 文件插件 mini-css-extract-plugin
一起使用,先将 CSS 文件分离,再进行 CSS Tree Shaking
。webpack.prod.js 配置方式如下:
const glob = require('glob')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const PurgeCSSPlugin = require('purgecss-webpack-plugin')const paths = require('paths')module.exports = { plugins: [ // 打包体积分析 new BundleAnalyzerPlugin(), // 提取 CSS new MiniCssExtractPlugin({ filename: "[name].css", }), // CSS Tree Shaking new PurgeCSSPlugin({ paths: glob.sync(`${paths.appSrc}/**/*`, { nodir: true }), }), ]}