Skip to main content

webpack 优化前端性能

随着前端的项目逐渐扩大,必然会带来性能问题。

项目在完成后会通过 webpack 进行打包,利用 webpack optimization 对前端项目性能优化是一个十分重要的环节。

通过 webpack 优化前端的手段有:

  • JS 代码压缩
  • CSS 代码压缩
  • HTML 代码压缩
  • 文件大小压缩
  • 图片压缩
  • Tree Shaking
  • 代码分离

一、JS 代码压缩

TerserWebpackPlugin 插件使用 terser 来压缩 JavaScript。

production 模式下,webpack 默认用 TerserPlugin 来处理代码。如果要进行自定义配置,需要执行以下步骤:

安装 terser-webpack-plugin:

yarn add terser-webpack-plugin -D

设置 webpack 配置文件:

webpack.config.js
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
...
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true // 电脑 cpu 核数 -1
})
]
}
}

TerserPlugin 属性说明:

  • test:用来匹配需要压缩的文件,默认为 /\.m?js(\?.*)?$/i
  • include:匹配参与压缩的文件,默认为 undefined
  • exclude:匹配不需要压缩的文件,默认为 undefined
  • parallel:使用多进程并发运行提高构建的速度,默认为 true,并发运行的默认数量为 os.cpus().length - 1
  • minify:允许自定义压缩函数,默认为 TerserPlugin.terserMinify,使用 terser 库;
  • terserOptions:设置 terser 配置项
  • extractComments:是否将注释抽取到单独的文件中,默认为 true,开发阶段可设置为 false,不保留注释。

二、CSS 代码压缩

CSS 压缩通常是去除无用的空格等,可以使用 css-minimizer-webpack-plugin 插件来实现:

yarn add css-minimizer-webpack-plugin -D

配置如下:

webpack.config.js
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')

module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin({
parallel: true
})
]
}
}

三、HTML 代码压缩

使用 HtmlWebpackPlugin 插件来生成 HTML 模板时,通过配置属性 minify 进行 HTML 优化:

yarn add html-webpack-plugin -D

配置如下:

webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
// ...
plugin: [
new HtmlwebpackPlugin({
...
minify: {
minifyCSS: false, // 是否压缩 CSS
collapseWhitespace: false, // 是否折叠空格
removeComments: true // 是否移除注释
}
})
]
}

设置了 minify,实际会使用另一个插件 html-minifier-terser

四、文件大小压缩

对文件的大小进行压缩,减少 HTTP 传输过程中宽带的损耗:

yarn add compression-webpack-plugin -D

配置如下:

webpack.config.js
const CompressionPlugin = require("compression-webpack-plugin");

module.exports = {
// ...
plugins: [
new ComepressionPlugin({
test: /\.(css|js)$/, // 哪些文件需要压缩
threshold: 500, // 设置文件多大开始压缩
minRatio: 0.7, // 至少压缩的比例
algorithm: 'gzip' // 采用的压缩算法
})
],
};

五、图片压缩

一般在打包后,图片文件的大小远比 js 或 css 文件大,所以图片压缩较为重要,可以用 image-webpack-loader 来实现。

yarn add image-webpack-loader -D

配置如下:

module: {
rules: [
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
// 压缩 jpeg 的配置
mozjpeg: {
progressive: true,
quality: 65
},
// 使用 imagemin**-optipng 压缩 png,enable: false 为关闭
optipng: {
enabled: false
},
// 使用 imagemin-pngquant 压缩 png
pngquant: {
quality: '65-90',
speed: 4
},
// 压缩 gif 的配置
gifsicle: {
interlaced: false
},
// 开启 webp,会把 jpg 和 png 图片压缩为 webp 格式
webp: {
quality: 75
}
}
}
]
}
]
}

六、Tree Shaking

Tree Shaking 表示消除死代码(JS 上下文中未引用的代码),依赖于 ES Module 的静态语法分析(不执行任何的代码,可以明确知道模块的依赖关系)

webpack 中实现 Tree Shaking 有两种方式:

  • usedExports:通过标记某些函数是否被使用,之后通过 terser 来进行优化;
  • sideEffects:跳过整个模块/文件,直接查看该文件是否有副作用。

1、usedExports

usedExports 配置只需将 usedExports 设为 true

module.exports = {
// ...
optimization: {
usedExports
}
}

配置后,未被引用的代码在 webpack 打包中会加入 unused harmony export mul 注释,用来告知 Terser 在优化时,可以删除掉这段代码,terser 在优化时会将该函数去掉。

/* unused harmony export mul */
function sum(num1, num2) {
return num1 + num2
}

2、sideEffects

sideEffects 用于告知 webpack compiler 哪些模块时有副作用,sideEffects 的方式更为有效,因为它允许跳过整个模块/文件和整个文件子树。

这里的副作用是在导入时会执行特殊行为的代码,而不是仅暴露一个 export 或多个 export。例如 polyfill,它影响全局作用域,并且通常不提供 export。

配置方法:

package.json 中设置 sideEffects 属性:

{
"name": "your-project",
"sideEffects": false
}

设为 false 即告知 webpack 可以安全的删除未引用的 exports。

如果有些文件需要保留,可以设置为数组的形式:

{
"name": "your-project",
"sideEffects": [
"./src/util/format.js",
"*.css" // 所有的 css 文件
]
}

除了 JS,css 也能实现 tree shaking。

3、css tree shaking

css 进行 tree shaking 优化可以安装 PurgeCss 插件:

yarn add purgecss-plugin-webpack -D

配置如下:

webpack.config.js
const PurgeCssPlugin = require('purgecss-webpack-plugin')

module.exports = {
...
plugins: [
new PurgeCssPlugin({
path: glob.sync(`${path.resolve('./src')}/**/*`),
{
nodir: true
} // src 里面的所有文件
satelist: function () {
return {
standard: ["html"]
}
}
})
]
}

其中,paths 表示要检测哪些目录下的内容需要被分析,配合使用 glob。

默认情况下,Purgecss 会将 HTML 标签的样式移除掉,如果希望保留,可以添加 safelist 的属性。

七、代码分离

默认情况下,所有的 JS 代码在首页会全部加载,会影响首页的加载速度,可以将代码分离到不同的 bundle 中,然后按需加载,提高代码的加载性能。

可以通过 webpack 自带的 splitChunksPlugin 来实现。

默认配置如下:

module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async', // 对同步代码还是异步代码进行处理
minSize: 20000, // 生成 chunk 的最小体积
minRemainingSize: 0,
minChunks: 1, // 被引入的次数
maxAsyncRequests: 30,
maxInitialRequests: 30,
enforceSizeThreshold: 50000,
cacheGroups: {
defaultVendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10,
reuseExistingChunk: true
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
}

点击查看更多 splitChunks 配置属性