webpack笔记(6)-构建速度和体积优化策略

141 阅读1分钟

使用内置的stats

stats是构建的统计信息

//  添加命令
"build:stats": "webpack --config webpack.prod.js --json > stats.json"

生成stats文件,颗粒度比较粗。

打包速度分析

可以使用speed-measure-webpack-plugin插件

// webpack.prod.js中
// 1.定义插件对象
const smp = new SpeedMeasureWebpackPlugin();
// 2.包裹要分析的内容
module.exports = smp.wrap({
    ...
});

执行命令后,结果如下:

image.png 可以分析打包总耗时,分析每个插件和loader耗时的情况,红色需要优化。

打包体积分析

可以使用webpack-bundle-analyzer

const {BundleAnalyzerPlugin} = require('webpack-bundle-analyzer');
plugins: [
    new BundleAnalyzerPlugin()
]

启动项目后会自动打开浏览器,根据提示进行体积分析

多进程/多实例构建

使用thread-loader,将打包任务划分为多个node进程,将模块分给多个进程

rules: [
    {
        test: /.js$/,
        use: [
            {
                loader: 'thread-loader',
                options: {
                    workers: 3
                }
            },
            'babel-loader'
        ]
    }
]

效果有待确认,目前项目小,还看不出来,反而反向优化了。(进程的开销也是需要时间的。在项目较小时,反而是负优化)

并行压缩

使用terser-webpack-plugin插件,开启parallel参数

optimization: {
    minimizer: [
        new TerserPlugin({
            parallel: true
        })
    ]
}

测试效果依旧不明显

预编译资源模块-dll

  • 思路:将react、react-dom、redux、react-redux基础包和业务基础包打包成一个文件
  • 方法:使用 DllPlugin 进行分包,DllReferencePlugin 对 manifest.json 引用

实现步骤:
1.新建webpack.dll.js

const path = require('path');
const webpack = require('webpack');

module.exports = {
    entry: {
        // 多个包可以在entry中新增一个key
        bundleLibrary: [
            'react',
            'react-dom'
        ]
    },
    output: {
        filename: '[name].dll.js',
        // 输出的位置
        path: path.join(__dirname, 'build/library'),
        library: '[name]'
    },
    // 生成manifest.json
    plugins: [
        new webpack.DllPlugin({
            name: '[name]_[hash]',
            path: path.join(__dirname, 'build/library/[name].json')
        })
    ]
}

2.新增命令行

"dll": "webpack --config webpack.dll.js"

执行命令后,文件新增

image.png

3.webpack.prod.js中引入

plugins: [
    new webpack.DllReferencePlugin({
        manifest: require('./build/library/bundleLibrary')
    })
]

执行构建命令后,文件打包体积变小

image.png 问答:dll的方式好像在webpack4里面应用的不是很多了,webpack4已经做了优化,我查看了下vue-cli以及create-react-app都抛弃了这个配置,具体原因地址:github.com/vuejs/vue-c…
解答:是的,如果项目使用了 Webpack4,确实对 dll 的依赖没那么大,使用 dll 相对来说提升也不是特别明显。而且有 hard-source-webpack-plugin 可以极大提升二次构建速度。
不过从实际前端工程中来说, dll 还是很有必要掌握的。对于一个团队而言,基本是采用相同的技术栈,要么 React、要么Vue 等等。这个时候,通常的做法都是把公共框架打成一个 common bundle 文件供所有项目使用。比如我们团队会将 react、react-dom、redux、react-redux 等等打包成一个公共库。dll 可以很好的满足这种场景:将多个npm包打成一个公共包。因此团队里面的分包方案使用 dll 还是很有价值,常见的会从整个工程的角度分为基础包(react、redux等)、业务公共包(所有业务都要用到的监控上报脚本、页面初始化脚本)、某个业务的js。

问答:dllplugin和splitChunks可以一起用吗?有没有什么区别和联系?
解答:可以一起使用。 DllPlugin 通常用于基础包(框架包、业务包)的分离。
SplitChunks 虽然也可以做 DllPlugin 的事情,但是更加推荐使用 SplitChunks 去提取页面间的公共 js 文件。因为使用 SplitChunks 每次去提取基础包还是需要耗费构建时间的,如果是 DllPlugin 只需要预编译一次,后面的基础包时间都可以省略掉。

webpack5的新方式?

开启缓存

babel-loader 开启缓存
terser-webpack-plugin 开启缓存
使用 cache-loader 或者 hard-source-webpack-plugin

optimization: {
    minimizer: [
        new TerserPlugin({
            parallel: true,
            cache: true
        })
    ]
}

运行后,在node_modules目录中会出现一个cache文件夹,再次执行就会缓存。

image.png 使用前: image.png 使用后: image.png 项目大会提升会更明显

缩小构建目标

  • 尽可能少构建模块,比如 bebel-loader 不解析 node_modules
  • 优化resolve.modules配置(减少模块搜索层级,就在配置的目录中找),从当前项目里面找,没找到会去node_modules中找,依次往父目录中找这些模块是否存在。比如第三方包我们放到node_modules中,那就没有必要从当前项目里面一层一层找。
  • 优化resolve.mainFields配置,即优化入口文件,只查找package.json中的main字段
  • 优化resolve.extensions配置(配置什么就只查找带该后缀的文件),不写后缀时默认匹配的后缀,减少各种试验的次数以增加速度
  • 合理使用alias,在指定路径查找
resolve: {
    alias: {
        'react': path.resolve(__dirname, './node_modules/react/umd/react.production.min.js'),
        'react-dom': path.resolve(__dirname, './node_modules/react-dom/umd/react-dom.production.min.js')
    },
    modules: [path.resolve(__dirname, 'node_modules')],
    extensions: ['.js'],
    mainFields: ['main']
}
rules: [
    {
        test: /.js$/,
        // 只解析src,或者exclude: 'node_modules'
        include: path.resolve('src'),
        use: [
            {
                loader: 'thread-loader',
                options: {
                    workers: 3
                }
            },
            'babel-loader',
            // 'eslint-loader'
        ]
    }
]

擦除无用的css和图片压缩

擦除无用的css使用purgecss-webpack-plugin插件
图片压缩使用image-webpack-loader

使用动态polyfill服务优化构建体积

image.png polyfill-service原理:根据浏览器的ua下发不同的polyfill。对于已经支持es6语法的浏览器版本,就不会反悔对应的polyfill