《webpack性能优化总结》


2020-12-03 上次更新时间:4/29/2022, 9:34:08 AM 0 javascript

# 前言

当项目越来越大越来越复杂时,如何进行优化成为了必须解决的难题。webpack 官网也有针对性能优化给出了指南。详细内容可看 —— 《webpack指南》

本文也对 webpack 性能优化做一下总结。webpack 性能优化可以从两大方面进行优化,一个是优化打包构建,一个是优化代码产出。下面针对这两个方面分别介绍。

# 优化打包构建

# 1.开启自动刷新

启用 Watch 模式。这意味着在初始构建之后,webpack 将继续监听任何已解析文件的更改。

webpack-dev-server 和 webpack-dev-middleware 里 Watch 模式默认开启。

// 开发环境
module.exports = {
    watch: true, // 开启监听,默认为false

    // 监听配置
    watchOptions: {
        ignored: /node_modules/,
        // 监听到变化后等待 300ms 再执行,防止文件更新太快导致重新编译效率太高
        aggregateTimeout: 300, // 默认为 300ms
        // 轮询文件是否发生变化
        poll: 1000 // 默认每隔 1000ms 询问一次
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 2.开启热更新

上面的自动刷新会刷新整个页面,如果想不刷新页面又要实现刷新,就需要开启热更新。

通过 HotModuleReplacementPlugin 插件可以实现。

// 开发环境
const webpack = require('webpack')
module.exports = {
    mode: 'development',
    plugins: [
        new webpack.HotModuleReplacementPlugin()
    ]
}
1
2
3
4
5
6
7
8

如果使用了webpack-dev-server,只需要配置 devServer.hot 即可。设置后 webpack 会默认引入 HotModuleReplacementPlugin。

module.exports = {
    mode: 'development',
    devServer: {
        hot: true
    }
}
1
2
3
4
5
6

《webpack实现热更新(HMR)原理分析》

# 3.优化 babel-loader

babel-loader 开启缓存 loader 的执行结果,并设置范围。

module.exports = {
	module:{
        rules: [
            {
                test: /\.js$/,
                use: ['babel-loader?cacheDirectory'], // 开启缓存
                include: path.resolve(__dirname, 'src'), // 明确范围
                // exclude: path.resolve(__dirname, 'node_modules') // 排除范围,和 include 二选一即可
            }
        ]
	}
}

1
2
3
4
5
6
7
8
9
10
11
12
13

# 4.设置 noParse

配置 module.noParse 忽略一些大型的 library 可以提高构建性能。

module.exports = {
	module:{
		noParse: /jquery|lodash/,// 不解析 jquery 和 |lodash
	}
}
1
2
3
4
5

# 5.配置 IgnorePlugin

配置 IgnorePlugin 可以忽略某些内容不参与打包。

module.exports = {
    plugins: [
        new webpack.IgnorePlugin({
            // 忽略 moment 的本地化内容
            resourceRegExp: /^\.\/locale$/,
            contextRegExp: /moment$/
        })
    ]
}
1
2
3
4
5
6
7
8
9

# 6.使用 DLLPlugin 预编译

DLL(Dynamic Link Library) 文件为动态链接库文件,在 Windows 中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即 DLL 文件,放置于系统中。当我们执行某一个程序时,相应的 DLL 文件就会被调用。

通常来说,我们的代码都可以至少简单区分成业务代码第三方库。如果不做处理,每次构建时都需要把所有的代码重新构建一次,耗费大量的时间。然后大部分情况下,很多第三方库的代码并不会发生变更(除非是版本升级),这时就可以用到dll:把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码

webpack 提供了内置插件 DLLPlugin ,它跟 output.library 的选项相结合可以暴露出 全局 dll 函数。

配置:webpack.dll.js

module.exports = {
    entry: {
        react: ['react', 'react-dom']
    },
    output: {
        filename: '[name].dll.js',
        path: distPath,
        library: '[name]_dll_[hash]' // 第三方库名,加上 _dll_ 避免全局变量冲突
    },
    plugins: [
        new webpack.DllPlugin({
            name: '[name]_dll_[hash]',
            // 描述动态链接库的 manifest.json 文件输出时的文件名称
            path: path.join(distPath, '[name].manifest.json')
        })
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

使用:webpack.config.js

module.exports = {
    plugins: [
        new webpack.DllReferencePlugin({
            manifest: require(path.join(distPath, 'react.manifest.json'))
        })
    ]
}
1
2
3
4
5
6
7

# 7.使用 HappyPack

使用 happypack 可以开启多进行打包,提高构建速度。

注意!创建子进程和子进程和主进程之间通信也是有开销的,如果项目很小也加上了 happypack,可能会编译的更慢!

const HappyPack = require('happypack');
// 线程池
const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length });

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                // 把对js文件的处理转交给 id 为 babel的 Happypack 实例
                use: ['happypack/loader?id=babel'],
                include: path.resolve(__dirname, 'src')
            },
            {
                test: /\.less$/,
                use: 'happypack/loader?id=styles'
            }
        ]
    },
    plugins: [
        new HappyPack({
            id: 'babel', // id 标识
            threadPool: happyThreadPool, // 共享线程池
            loader: ['babel-loader?cacheDirectory']
        }),
        new HappyPack({
            id: 'styles', // id 标识
            threadPool: happyThreadPool, // 共享线程池
            loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
        })
    ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 8.使用 thread-loader

除了使用 Happypack 外,还可以使用 thread-loader ,把 thread-loader 放置在其它 loader 之前,那么放置在这个 loader 之后的 loader 就会在一个单独的 worker 池中运行。

在 worker 池中运行的 loader 是受到限制的。例如:

  • 这些 loader 不能生成新的文件
  • 这些 loader 不能使用自定义的 loader API(也就是说,不能通过插件来自定义)
  • 这些 loader 无法获取 webpack 的配置
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        use: [
          "thread-loader",
          // 耗时的 loader (例如 babel-loader)
          "babel-loader"
        ]
      }
    ]
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

thread-loader 和 Happypack 构建时间基本没什么差别,不过 thread-loader 配置起来为简单。

# 9.使用 ParallelUglifyPlugin

webpack 默认提供了 UglifyJsPlugin 来压缩JS代码,但是它使用的是单线程压缩代码,也就是说多个js文件需要被压缩,它需要一个个文件进行压缩。

ParallelUglifyPlugin 可以会开启多个子进程,把对多个文件压缩的工作分别给多个子进程去完成,但是每个子进程还是通过 UglifyJS 去压缩代码。

注意!开启多进程是有开销的,如果项目很小也开启了,可能会变得更慢!

// 生产环境
import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin';

module.exports = {
  plugins: [
    new ParallelUglifyPlugin({
      uglifyJS: {
        output: {
          beautify: false, // 紧凑输出,没有空格
          comments: false // 删除所有注释
        },
        compress: {
            drop_console: true, // 删除所有 console 语句,可以兼容ie
            warnings: false, // 删除 UglifyJS 在没有用到的代码时输出警告信息
            collapse_vars: true, // 内嵌只使用了一次的变量,不做转换(如将 var x = 1; y = x, 转换成 y = 5)
            /*
            * 提取出现了多次但是没有定义成变量去引用的静态值,比如将 x = 'xxx'; y = 'xxx'  转换成
            * var a = 'xxxx'; x = a; y = a; 默认为不转换,为了达到更好的压缩效果,可以设置为false
            */
            reduce_vars: true
        }
      }
    })
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 优化产出代码

# 1.设置production模式

设置 production 模式也是优化的方法之一。(虽然这是已经是一个非常常用的配置了)

module.exports = {
    mode: 'production'
}
1
2
3

设置 production 模式有以下好处:

  • 自动压缩代码(webpack4.x后支持),也可以自己配置 ParallelUglifyPlugin
  • vue、react 等会自动删除调试代码(如开发环境的 warning)
  • 自动开启 Tree-Shaking:删除没有使用到模块(必须使用ES6 module(因为是静态引入)才会生效,如果使用commonJS(动态引入无法检测)则不生效)

# 2.压缩JS

Js 压缩可以使用下面的插件实现:

按需选取,如果需要压缩 ES6 代码,就用 terser-webpack-plugin

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
    mode: 'production',
    optimization: {
        minimizer: [
            // 使用 terser-webpack-plugin
            new TerserPlugin({
                terserOptions: {
                    // ...
                }
                include: /\/src/, // 明确范围
                parallel: true, // 开启多进程
            }),
            // 使用 uglifyjs-webpack-plugin
            new UglifyJSPlugin({
                uglifyOptions: {
                    warnings: false,  // 删除无用代码时不输出警告
                    compress: {
                        drop_console: true,  // 删除所有console语句,可以兼容IE
                        collapse_vars: true,  // 内嵌已定义但只使用一次的变量
                        reduce_vars: true,  // 提取使用多次但没定义的静态值到变量
                    },
                },
                output: {
                    beautify: false, // 最紧凑的输出,不保留空格和制表符
                    comments: false, // 删除所有注释
                },
                sourceMap: false, // 是否开启sourceMap
                extractComments: false, // 是否提取注释到单独的文件中
                cache: true, // 开启缓存
                parallel: true // 开启多进程
            })
        ]
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 3.压缩Css

Css 的处理可以使用下面的插件:

const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    optimization: {
        minimizer: [
            new OptimizeCSSPlugin({
                cssProcessorPluginOptions: {
                    preset: ['default', { 
                        mergeLonghand: false,
                    }]
                }
            })
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: utils.assetsPath('css/[name].[contenthash:29].css'),
            allChunks: true
        }),
        // 也可以放在这里
        // new OptimizeCSSPlugin({
        //     cssProcessorPluginOptions: {
        //         preset: ['default', { 
        //             mergeLonghand: false,
        //         }]
        //     }
        // })
    ]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# 4.压缩图片

一般图片在使用前,都会使用 tiny.png 手动压缩。如果嫌麻烦也可以借助image-webpack-loader实现自动压缩。

image-webpack-loader 是基于 imagemin 这个 Node 库来实现图片压缩的。

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name]_[hash].[ext]',
                            outputPath: 'images/',
                        }
                    },
                    {
                        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
                            }
                        }
                    }
                ]
            }
        ]
    } 
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# 5.小图片使用base64编码

关于文件的处理,一般使用下面两个 loader:

其中 url-loader 功能类似于 file-loader,但是在文件大小(单位 byte)低于指定的限制时,可以返回一个 DataURL(base64),可以减少请求次数。

module.exports = {
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000, // 小于100kb的图片转换为base64
                    name: utils.assetsPath('img/[name].[hash:7].[ext]')
                }
            }
        ]
                  
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 6.提取公共代码

通过配置 optimization.splitChunks 使用 SplitChunksPlugin 插件可以提取公共模块代码。公共模块文件在最开始的时候加载一次,便存到缓存中供后续使用,大大提升了访问速度。

从 webpack4.0 后,CommonsChunkPlugin 已经被移除,更改为使用 SplitChunksPlugin。

module.exports = {
    optimization: {
        splitChunks: {
            chunks: 'initial', // 代码分隔模式。initial:同步代码分割 ,async:异步代码分割,all:同步异步分割都开启
            minSize: 30000, // 字节 引入的文件大于30kb才进行分割
            cacheGroups: {
                // 创建一个commons块,其中包括入口点之间共享的所有代码
                common: {
                    test: /src/,
                    chunks: 'initial',
                    minChunks: 9, // 模块至少使用次数
                    name: 'common',
                    priority: 9, // 优先级,先打包到那个组里面,值越大,优先级越高
                    enforce: true
                },
                /**
                 * webpack 默认有 vendor 配置,自定义配置会覆盖原来的
                 */
                // 创建一个vendors块,其中包括node_modules整个应用程序中的所有代码
                vendor: {
                    test: /node_modules/,
                    chunks: 'initial',
                    minChunks: 9,
                    name: 'vendor',
                    priority: 10,
                    enforce: true
                }
            }
        },
        runtimeChunk: { // 向仅包含运行时的每个入口点添加一个代码块
            name: 'manifest'
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

# 7.开启Scope Hosting

使用 ModuleConcatenationPlugin 插件可以实现预编译功能。使用这个插件可以将一些工具类模块预编译到一个闭包中,在其他模块加载前先加载这个模块,这种行为称为 Scope Hosting(作用域提升)。

必须使用 ES6 的 module 语法,否则 webpack 会自动回退到普通打包。

module.exports = {
    resolve: {
        // 针对 npm 中第三方模块优先采用 jsnext:main 中指向的 ES6 模块语法的文件
        maniFields: ['jsnext:main', 'browser', 'main']
    }
    plugins: [
        // 开启 Scope Hosting
        new webpack.optimize.ModuleConcatenationPlugin()
    ]
}
1
2
3
4
5
6
7
8
9
10

ModuleConcatenationPlugin 可以实现代码合并(必须使用ES6 module 的文件),它有以下好处:

  • 代码体积更小
  • 创建函数作用域更少
  • 代码可读性更好

# 8.开启gzip压缩

使用 compression-webpack-plugin 可以提供带 Content-Encoding 编码的压缩版的资源。如下图:

注意:需要服务端同步支持。

开启gzip压缩

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

module.exports = {
    mode: 'production',
    plugins: [
        new CompressionWebpackPlugin({
            asset: '[path].gz[query]',
            algorithm: 'gzip',
            test: new RegExp('\\.(js|css)$'),
            threshold: 10240,
            minRatio: 0.8
        })
    ]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

服务端支持(nginx)

server {
    listen 9000;
    server_name localhost; # 您的实际 ip 或者域名
    client_max_body_size 20M;
    root /home/data; # 静态资源文件存放路径

    # gzip
    gzip on;
    gzip_min_length 1k;
    gzip_vary on;
    gzip_buffers  4 16k;
    gzip_comp_level 2;

    # 所有静态资源及缓存
    location ~* .*\.(jpg|gif|jpeg|css|png|js|wasm) {
        expires 10d;
    }
    # ...
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

压缩前资源大小和请求时间:2.5MB,30s

压缩后资源大小和请求时间:626KB,1.22s

基本原理

  • 浏览器请求资源文件时会自动带一个 Accept-Encoding 的请求头告诉服务器支持的压缩编码类型

  • 服务器配置开启gzip选项:接收客户端资源文件请求,查看请求头Content-encoding支持的压缩编码格式,如果是包含gzip那么在每次响应资源请求之前进行gzip编码压缩后再响应返回资源文件(在响应头会带上Content-encoding: gzip)

  • 浏览器接收到响应后查看请求头是否带有 Content-encoding:gzip,如果有进行对返回的资源文件进行解压缩然后再进行解析渲染

注意点

  • 低版本浏览器兼容性,服务器可以设置一些忽略规则忽略为浏览器
  • 媒体文件无需开启:图片、音乐和视频大多数都已压缩过了,HTML,CSS AND JAVARSCRIPT
  • CPU负载:压缩文件耗费CPU(服务器需要压缩文件、浏览器解压文件)

# 9.懒加载

懒加载是基于code-splitting的。不切割代码,所有的文件都揉合在一个 js 里面,就无法实现懒加载了。

关于懒加载,不同的框架有不同的实现,下面介绍基于 vue 的懒加载:

# 1. 路由懒加载

路由懒加载

设置 webpackChunkName,可以将某个路由下的所有组件都打包在同个异步块 (chunk) 中。

const router = new VueRouter({
  routes: [
    { path: '/foo', component: () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') },
    { path: '/bar', component: () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') }
  ]
})
1
2
3
4
5
6

# 2. 组件懒加载(异步组件)

vue 提供多种异步组件注册方式,详细介绍请看官网介绍 - 异步组件

局部注册

<template>
  <div id="app">
    <async-component></async-component>
  </div>
</template>
<script>
export default {
  name: 'App',
  components: {
      'async-component': function (resolve) {
          //延时演示
          setTimeout(function () {
              // 这个特殊的 `require` 语法将会告诉 webpack自动将你的构建代码切割成多个包,这些包会通过 Ajax 请求加载
              require(['./components/AsyncComponent.vue'], resolve)
          }, 5000);
      }
  }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 3. vuex状态懒加载

使用 store.registerModule 可以注册一个动态模块。

const store = new Vuex.Store()

...

// 一些条件判断
import('./store/login').then(loginModule => {
  store.registerModule('login', loginModule)
})
1
2
3
4
5
6
7
8

# 10.UI框架按需引入

有时候引入了某个UI框架,如 elementUIAnt Design 等,但实际上使用的只有几个组件,如果全部引入显得有点多余。这时可以借助 babel-plugin-component,只引入需要的组件,减少项目体积。

  1. 安装 babel-plugin-component
npm install babel-plugin-component -D
1
  1. 修改 .babelrc
{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
  1. 使用
import Vue from 'vue';
import { Button } from 'element-ui';
import App from './App.vue';

Vue.use(Button)

new Vue({
  el: '#app',
  render: h => h(App)
});
1
2
3
4
5
6
7
8
9
10

# 11.利用Tree-Shaking

在项目中使用 ES6 Modules 语法,以保证 Tree-Shaking 起作用。

如果使用 commonJs 的语法 require 一个模块,是无法 Tree-Shaking 的。

# 12.使用 CDN 加速

通过设置 publicPath 为 CDN 路径,可以加快访问速度( 前提是打包构建后资源需要上传到 CDN)。

使用 CDN 加速不一定需要设置 publicPath,可以让运维在 cdn 配置一个链接指向该项目即可。

module.exports = {
  output: {
    publicPath: 'https://cdn',
  }
}
1
2
3
4
5

打包后资源路径已经加上了cdn前缀

# 13.利用缓存

利用浏览器缓存文件,当代码文件没变化的时候,用户就只需要读取浏览器缓存的文件即可,提高访问速度。

合理使用缓存流程:

  1. 代码分割(code splitting):一般来说 javascript 文件使用 [chunkhash]、css 文件使用 [contenthash]、其他资源(例如图片、字体等)使用 [hash]
  2. 提取公共代码
  3. 抽取 webpack 的 runtime 代码
  4. 配置 moduleIds 计算方式

不同版本的配置 moduleIds 计算方式

  • webpack v4.0 之前需要借助 HashedModuleIdsPlugin 插件配置
  • webpack v4.0 开始可以通过配置 optimization.moduleIds, 默认值是 false
  • webpack v5.0 版本已经默认配置了 optimization.moduleIds: 'deterministic',不需要手动设置
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].[chunkhash].js', // js 使用 [chunkhash]
        path: path.resolve(__dirname, 'dist'),
    },
    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 20000,
                    // 图片、字体资源使用 [hash]
                    name: utils.assetsPath('img/[name].[hash:7].[ext]')
                }
        ]
    },
    optimization: {
        moduleIds: 'deterministic', // 告知 webpack 当选择模块 id 时需要使用哪种算法
        runtimeChunk: 'single', //  将 runtime 代码拆分为一个单独的 chunk
        splitChunks: {
            cacheGroups: {
                vendor: { // 将第三方库提取到单独的 chunk
                    test: /[\\/]node_modules[\\/]/,
                    name: 'vendors',
                    chunks: 'all',
                }
            }
        }
    },
    plugins: [
        new MiniCssExtractPlugin({
            // css 文件使用 [contenthash]
            filename: utils.assetsPath('css/[name].[contenthash:29].css'),
            allChunks: true
        })
    ]
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

# 其他优化

# 1.升级webpack版本

升级 webpack 的版本,无论是打包构建还是产出代码,都会有大幅的提升。当然,升级后需要做好全面测试。

# 2.区分打包环境配置

开发环境和生产环境的配置应该区分,根据需求进行配置。像HMR用在生产环境是没有意义的,开发环境使用TerserPlugin压缩也没必要。

# 3.良好的编码规范

编写代码的时候遵守代码规范,养成良好的习惯。合理规划项目结构,抽离公共组件、公共方法,避免产生冗余代码。使用 ES6 module 好让 Tree-Shaking 生效等等。从每一个小地方做好优化。

# 分析工具

# 体积大小分析

webpack-bundle-analyzer :打包分析神器,通过界面化显示每个包的大小和依赖。

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
    plugins: [
        new BundleAnalyzerPlugin()
    ]
}
1
2
3
4
5
6
7

运行后会自动打开浏览器,也可以手动打开链接 http://127.0.0.1:8888

# 构建速度分析

使用 speed-measure-webpack-plugin 可以看到构建期间各个阶段花费的时间

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();

const webpackConfig = smp.wrap({
    module: {
        rules: [
            // ...
        ]
    },
    plugins: [
        // ...
    ]
});

module.exports webpackConfig;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

执行后输出,可以看到每个loader 和 plugin 的执行时间

# 最后

关于优化,其实就是涉及到 压缩缓存明确打包范围抽取公共代码按需加载预编译开启多线程等方面。

其实上文很多优化方法已经是默认的配置,特别是使用了 vue-cli3 搭建的框架,默认配置还被隐藏了。但还是可以了解下,知道是这些配置做了优化。

上次更新时间: 4/29/2022, 9:34:08 AM