一、缩小文件搜索范围

1. 减少loader处理的文件

loader对文件的转换操作很耗时,因此我们最好精准匹配要转换的文件

loader 可以通过 options 对象配置(仍然支持使用 query 参数来设置选项,但是这种方式已被废弃)。

babel-loader

用于转换ES6代码,文档说了它的几个特点:

  1. 慢!
  2. 代码体积变大! ```javascript // 转换前Vue-Cli默认配置: {
    1. test: /\.m?jsx?$/, // 项目中如果只有js文件就写js就好,提高正则表达式性能
    2. exclude: [
    3. function () { /* omitted long function */ }
    4. ],
    5. use: [
    6. /* config.module.rule('js').use('babel-loader') */
    7. {
    8. loader: 'D:\\CS\\Repositories\\project\\erabbit-pc-vue-project\\node_modules\\babel-loader\\lib\\index.js',
    9. options: {
    10. cacheCompression: false,
    11. cacheDirectory: 'D:\\CS\\Repositories\\project\\erabbit-pc-vue-project\\node_modules\\.cache\\babel-loader',
    12. cacheIdentifier: '26fa99d2'
    13. }
    14. }
    15. ]
    }

// 修改配置 { test: /.js$/, use: [ { loader: ‘babel-loader’, options: { cacheDirectory: true } } ], include: path.resolve(__dirname, ‘src’) }

  1. <a name="UwKna"></a>
  2. ## 2. 优化resolve.modules
  3. 用于配置去哪找第三方模块,默认值是 ['node_modules'],含义是先去当前目录下的 ./node_modules 目录下去找想找的模块,如果没找到就去上一级目录 ../node_modules 中找,再没有就去 ../../node_modules 中找,以此类推<br />当安装的第三方模块都放在项目根目录下的 ./node_modules 目录下时,没有必要按照默认的方式去一层层的寻找,可以指明存放第三方模块的绝对路径,以减少寻找.
  4. ```javascript
  5. // vue-cli默认配置
  6. modules: [
  7. 'node_modules',
  8. 'D:\\CS\\Repositories\\project\\erabbit-pc-vue-project\\node_modules',
  9. 'D:\\CS\\Repositories\\project\\erabbit-pc-vue-project\\node_modules\\@vue\\cli-service\\node_modules'
  10. ]
  11. // 修改
  12. resolve: {
  13. modules: [path.resolve(__dirname, 'node_modules')]
  14. }

3. 优化 resolve.mainFields 配置

用于配置第三方模块使用哪个入口文件,与target配置有关。
由于一些第三方模块可能可以支持不同的环境,会有多个不同的入口,但大多数都是以main为入口,不过我觉得这一项还是不要改好。

  1. resolve: {
  2. // 只采用 main 字段作为入口文件描述字段,以减少搜索步骤
  3. mainFields: ['main'],
  4. },

4. 配置resolve.alias

用于配置导入第三方模块时要加载的文件路径,比如一个包有一个入口文件,依赖于很多其它的文件,每次加载都需要去解析所有文件,一般包都会有一份打包好的生产环境的文件,可以配置别名为该文件路径,这样就可以直接加载,但是这样无法配置treeshaking去除重复代码。

5. 优化rsolve.extensions

当省略文件后缀时会采用该配置列表中的后缀去查找,列表越小越好,

  1. // 默认
  2. resolve: {
  3. // 尽可能的减少后缀尝试的可能性
  4. extensions: ['.js', '.json'],
  5. },
  6. // 修改
  7. extensions: ['.js']

6. 优化 module.noParse 配置

用于配置不需要解析的文件,忽略对部分没采用模块化的文件的递归解析处理,这样做的好处是能提高构建性能。如

  1. const path = require('path');
  2. module.exports = {
  3. module: {
  4. // 独完整的 `react.min.js` 文件就没有采用模块化,忽略对 `react.min.js` 文件的递归解析处理
  5. noParse: [/react\.min\.js$/],
  6. },
  7. };

二、thread-loader多进程处理

官方的一个loader(文档)
一般可以用于对babel-loader开启多进程,仅在耗时的操作中使用此 loader!
可能我的项目中js文件不多,感觉没啥提升

  1. // 安装
  2. yarn add thread-loader -D
  3. // 在耗时的loader如babel-loader前配置即可
  4. module: {
  5. rules: [
  6. {
  7. test: /\.js$/,
  8. use: [
  9. {
  10. loader: 'thread-loader'
  11. },
  12. {
  13. loader: 'babel-loader',
  14. options: {
  15. cacheDirectory: true
  16. }
  17. }
  18. ],
  19. include: path.resolve(__dirname, 'src')
  20. }
  21. ]
  22. },

三、构建速度分析插件

speed-measure-webpack-plugin

  1. // 安装
  2. yarn add -D speed-measure-webpack-plugin
  3. // 导入使用
  4. const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
  5. const smp = new SpeedMeasurePlugin()
  6. configureWebpack: smp.wrap({
  7. //...webpack的配置
  8. })

打包之后会在控制台输出,
image.png

四、使用 ParallelUglifyPlugin

由于压缩 JavaScript 代码需要先把代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理 AST,导致这个过程计算量巨大,耗时非常多。
插件github

  1. // 安装
  2. yarn add webpack-parallel-uglify-plugin -D
  3. const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin')
  4. plugins: [
  5. // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
  6. new ParallelUglifyPlugin({
  7. // 传递给 UglifyJS 的参数
  8. uglifyJS: {
  9. output: {
  10. // 最紧凑的输出
  11. beautify: false,
  12. // 删除所有的注释
  13. comments: false
  14. },
  15. compress: {
  16. // 在UglifyJs删除没有用到的代码时不输出警告,这一项报错说不支持wrnings
  17. // warnings: false,
  18. // 删除所有的 `console` 语句,可以兼容ie浏览器
  19. drop_console: true,
  20. // 内嵌定义了但是只用到一次的变量
  21. collapse_vars: true,
  22. // 提取出出现多次但是没有定义成变量去引用的静态值
  23. reduce_vars: true
  24. }
  25. }
  26. })
  27. ]

配置完打包发现时间反而上去了,插件自己就花了一秒多。