Webpack优化篇

329 阅读2分钟

前置

性能分析工具

这里使用 Webpack-bundle-analyzer

pnpm add progress-bar-webpack-plugin -D  

配置

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;  
module.exports = {  
    // ...  
    plugins: [  
        // 代码产物分析  
        new BundleAnalyzerPlugin(),  
    ],  
}  

分析界面(图片来自https://www.npmjs.com/package/webpack-bundle-analyzer)

webpack 构建流程

  • 初始化
  1. 根据配置文件、Shell 参数以及默认配置结合得出最终的配置参数
  2. 创建编译器对象 compiler
  3. 初始化编译环境
  4. 编译开始,执行 compiler 的 run 方法,创建 compilation 对象
  5. 确定入口
  • 构建
  1. 编译模块
  2. 完成编译模块,得到依赖关系图
  • 封装
  1. 根据依赖关系进行打包

  2. 对包进行优化,tree-shaking、压缩 等

  3. 写入系统

缓存

在 webpack 5 中提供了缓存的功能,通过 cache.type = 'filesystem' 即可开启持久化缓存。
开启持久化缓存后,webpack 会在首次构建时,将构建出的产物模块序列化然后保存到硬盘,后面再执行构建时,就可以跳过很多编译过程,直接复用缓存。

图像优化

压缩

关于图片压缩这里使用的是 image-webpack-loader

pnpm add -D image-webpack-loader  

配置

rules: [  
    {  
        test: /\.(gif|png|jpe?g|svg)$/i,  
        type: "asset/resource",  
        use: [{  
            loader: 'image-webpack-loader',  
            options: {  
                mozjpeg: {  
                    progressive: true,  
                    quality: 65,  
                }  
            }  
        }]  
    },  
]

options 有多种属性

  • mozjpeg:压缩 JPG(JPEG) 图片
  • optipng、pngquant:压缩 PNG 图片
  • svgo:压缩 SVG 图片
  • gifsicle:压缩 Gif 图
  • webp:将 JPG/PNG 图压缩并转化为 WebP 图片格式

打包体积优化

使用 cdn 分包

将项目中体积较大的包通过 cdn 的方式引入,减少打包产物体积大小。

pnpm add html-webpack-externals-plugin -D  

配置

plugins: [  
    // ...  
    new HtmlWebpackExternalsPlugin({  
        externals: [  
            {  
                module: 'react',  
                entry: 'https://unpkg.com/react@18.2.0/umd/react.production.min.js',  
                global: 'React',  
            },  
        ]  
    })  
],

这里以 react 为例,使用 cdn 的方式引入,不再打包进入产物

打包速度优化

多进程打包

pnpm add -D thread-loader  

配置

rules: [
    {  
        test: /\.js$/,  
        use: [  
            {  
                loader: "thread-loader",  
                options: {  
                    workers: 2,  
                    workerParallelJobs: 50,  
                },  
            },  
            // ...  
        ]  
    }  
] 
  • workers 进程总数

  • workerParallelJobs 单个进程中并发执行的任务数

  • poolTimeout 超时时间,子进程空闲超时会关闭

  • poolRespawn 是否允许子进程关闭后重新创建新的子进程

  • workerNodeArgs 设置启动子进程时,额外的参数

按需编译

webpack 提供一个实验特性 lazyCompilation用来实现异步引用模块的按需编译,极大提高了冷启动速度。

module.exports = {
    // ...
    experiments: {
        lazyCompilation: true,
    },  
};

但是该功能还处在实验阶段,最好只在开发环境使用

约束 loader 执行的范围

通过 module.rules.exclude / module.rules.include 可以进一步缩小 loader 的执行范围。

rules: [
    {
        test: /\.js$/,
        exclude: /node_modules/,
        // ...
    },  
],

使用 noParse

使用 module.noParse 跳过不需要二次编译的资源文件。

module.exports = {  
    //...  
    module: {  
        noParse: /lodash|react/,  
    },  
};  

关闭 ts 的类型检查

使用 fork-ts-checker-webpack-plugin 插件来进行 ts 的类型检查,该插件会将 ts 的类型检查和编译过程放在单独的进程中运行,然后我们关闭 ts-loader 的类型检查,提升编译速度。

pnpm add -D fork-ts-checker-webpack-plugin  

配置

const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {  
    module: {  
        rules: [{  
            test: /\.ts$/,  
            use: [  
                {  
                    loader: 'ts-loader',  
                    options: {  
                        // 仅编译  
                        transpileOnly: true  
                    }  
                }  
            ],  
        }, ],  
    },  
    plugins:[  
        new ForkTsCheckerWebpackPlugin()  
    ]  
};

代码压缩

代码压缩就是抛弃代码的可读性、格式化等等一切,把我们的代码做到最精简。

js 压缩

webpack 5 默认使用 terser 进行 js 压缩,通过 optimization.minimize 属性开启。

css 压缩

使用 css-minimizer-webpack-plugin 插件来完成对 css 的压缩

pnpm add -D css-minimizer-webpack-plugin  

配置

const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");  
module.exports = merge(common, {  
    optimization: {  
        minimize: true,  
        minimizer: [  
            new CssMinimizerPlugin(),  
        ],  
    },  
});  

该插件还可以通过 minify 属性来指定使用什么进行压缩,可选值:

  • CssMinimizerPlugin.cssnanoMinify 使用 cssnano 默认值,不需要额外安装依赖
  • CssMinimizerPlugin.cssoMinify 使用 csso
  • CssMinimizerPlugin.cleanCssMinify 使用 clean-css
  • CssMinimizerPlugin.esbuildMinify 使用 ESBuild
  • CssMinimizerPlugin.parcelCssMinify 使用 parcel-css

需要注意的是,该插件必须配合之前提到的 mini-css-extract-plugin 插件一起使用,mini-css-extract-plugin 插件将 css 代码抽离到一个文件,css-minimizer-webpack-plugin 再对代码进行压缩。

html 压缩

pnpm add -D html-minifier-terser  

配置

module.exports = merge(common, {  
    optimization: {  
        minimize: true,  
        minimizer: [  
            new TerserPlugin({  
                parallel: 2 // number | boolean  
            }),  
            new CssMinimizerPlugin({  
                minify: CssMinimizerPlugin.cssnanoMinify,  
            }),  
        ],  
    },  
});  

gzip

安装 CompressionWebpackPlugin

pnpm add -D compression-webpack-plugin  

配置

const CompressionPlugin = require('compression-webpack-plugin');

module.exports = {
    plugins: [
        new CompressionPlugin({
            algorithm: 'gzip',
            test: /\.(js|css)$/,
        }),
    ],
};