likes
comments
collection
share

一个前端项目的 webpack 调优记录

作者站长头像
站长
· 阅读数 16

前言

公司的一个核心前端项目是使用 vue-cli 脚手架生成的,用得较为老旧的技术栈(Vue2 + Webpack4),项目启动和打包非常慢,组内的前端同学已经无力吐槽,亟待升级优化。而最新的 webpack5 发布至今已经 2 年多了,刚好项目需求开发完有空余时间,便决定给项目来一次 webpack 调优改造,提升前端开发效率。

思路

思路很简单,我们先将核心依赖升级至最新版(v4 升级至 v5),对原 plugin、loader 进行按需替换及移除,按 developmentproduction 环境进行测试,解决升级过程中遇到的各种写法和兼容性问题。

项目旧依赖如下:

"webpack": "^4.20.2",
"webpack-bundle-analyzer": "^3.8.0",
"webpack-dev-middleware": "^3.4.0",
"webpack-hot-middleware": "^2.24.3",
"webpack-merge": "^4.1.4",

依赖升级

  1. 分别安装以下依赖:webpack-cliwebpackwebpack-merge
npm install webpack-cli webpack@latest webpack-merge@5 --save-dev
  1. 尝试打包
npm run build -- view=demo loginbg=szw loginicon=qhdata

一个前端项目的 webpack 调优记录

webpack-merge 升级到版本 5,merge 方法需要解构使用,涉及 webpack-merge 的地方统一修改导入方式;

const { merge } = require('webpack-merge')

启动

  • 浏览器控制台报错:Uncaught ReferenceError: process is not defined

一个前端项目的 webpack 调优记录

webpack.dev.conf.js 添加 DefinePlugin 设置

new webpack.DefinePlugin({ 'process.env': config.dev.env }),

一个前端项目的 webpack 调优记录

官方迁移文档提及到这部分:

一个前端项目的 webpack 调优记录

打包

  • TypeError: webpack.HashedModuleIdsPlugin is not a constructor

一个前端项目的 webpack 调优记录

移除 HashedModuleIdsPlugin 插件。

// new webpack.HashedModuleIdsPlugin()
  • 大段的报错信息,二分定位错误。项目的 webpack 配置生成是通过 webpack-merge 的方式生成,所以可先将 baseWebpackConfig 或 prodWebpackConfig 置为空对象,定位错误的配置项,缩小排查范围。

一个前端项目的 webpack 调优记录

分析 baseWebpackConfig 配置,需要对比 v4 和 v5 版本的配置项差异。

module.exports = {
  entry: {},
  output: {},
  node: {},
  externals: {},
  resolve: {},
  module: {},
  optimization: {},
  plugins: []
}

v4 版本

module.exports = {
    node: {
    dns: 'mock',
    fs: 'empty',
    path: true,
    url: false
  },
}

v5 版本

module.exports = {
  node: {
    global: false,
    __filename: false,
    __dirname: false,
  },
};

v4 关于 node 的设置项在 v5 版本的 webpack core 解析会出错。去除 node 配置项后重新 build,报错信息不再显示。

  • TypeError: compiler.plugin is not a function

一个前端项目的 webpack 调优记录

optimize-css-assets-webpack-plugin 插件版本太低,直接移除。

npm uninstall optimize-css-assets-webpack-plugin --save-dev
  • Error: Cannot find module 'webpack/lib/RuleSet'

一个前端项目的 webpack 调优记录

v5 版本内置了 inline 资源模块,不需要使用 svg-sprite-loader 处理 svg 文件,修改 svg 文件规则。

修改前:

{
  test: /\.svg$/,
  include: [resolve('src/icons')],
  use: {
        loader: 'svg-sprite-loader',
    options: {
      symbolId: 'icon-[name]',
    },
  },
},

修改后:

{
    test: /\.svg/,
    type: 'asset/inline'
}    
  • resolve.fallback,指定解析失败后,是否重定向模块请求,按提示添加即可。

一个前端项目的 webpack 调优记录

修改前:

resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
  },

修改后:

resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    fallback: {
      fs: false,
      path: false,
      crypto: false,
      url: false,
    },
  },
  • babel 默认处理文件大小设置

一个前端项目的 webpack 调优记录

修改 .babelrc 文件,添加 env 配置项:

"env": {
    "development": { "compact": false },
    "production": { "compact": false }
  }
  • [DEP_WEBPACK_CHUNK_MODULES_ITERABLE] DeprecationWarning: Chunk.modulesIterable: Use new ChunkGraph API

一个前端项目的 webpack 调优记录

升级 mini-css-extract-plugin 插件:

npm install mini-css-extract-plugin@latest --save-dev
  • [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future, all modifications are deprecated.

一个前端项目的 webpack 调优记录

升级 copy-webpack-plugin 插件:

npm install copy-webpack-plugin@latest --save-dev

优化

项目从启动到打包都存在着以下问题:

  • 启动、打包慢,平均耗时 3 分钟以上;
  • 冗余的控制台 log 非常多。

我们分别引入一些插件来解决下面的问题:

speed-measure-webpack-plugin

用于分析总打包耗时及每个 plugin、loader 的耗时情况,后续可用于定向优化。 在 webpack.dev.conf.js 中添加 speed-measure-webpack-plugin 处理:

const SpeedMeasurePlugin = require('speed-measure-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

const devWebpackConfig = merge(baseWebpackConfig, {
  mode: 'development',
  module: {},
  devtool: 'eval',
  plugins: [
    new webpack.DefinePlugin({ 'process.env': config.dev.env }),

    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: 'index.html',
      inject: true,
    }),
    new FriendlyErrorsPlugin(),
  ],
})

/**
 * speed-measure-webpack-plugin 与 vue-loader-plugin 插件不兼容
 * 不兼容的插件在 wrap 之后再 push plugins
 */
const smp = new SpeedMeasurePlugin()
const smpWrapWebpackConfig = smp.wrap(devWebpackConfig)
smpWrapWebpackConfig.plugins.push(new VueLoaderPlugin())
smpWrapWebpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin())

module.exports = smpWrapWebpackConfig

项目的耗时情况如下:

一个前端项目的 webpack 调优记录

可以看到,vue-loader 耗时占用最高,这是因为项目存在非常多的 .vue 文件(数量多达 1693 个)。

一个前端项目的 webpack 调优记录

progress-bar-webpack-plugin

一个可用于查看当前的任务进度插件,在 webpack.base.conf.js 中添加配置:

const ProgressBarPlugin = require('progress-bar-webpack-plugin')

module.exports = {
  ...
  plugins: [
     new ProgressBarPlugin({ format: `xxxx-任务极速处理中:  :msg [:bar] ${chalk.green.bold(':percent')} (:elapsed s)` }),
  ],
}

一个前端项目的 webpack 调优记录

loader 写法简化

未添加配置项的,直接使用名称即可,看起来更简洁。

修改前:

{
  test: /\.less$/,
    use: [
      {
        loader: 'thread-loader',
      },
      {
        loader: 'vue-style-loader',
      },
      {
        loader: 'css-loader',
      },
      {
        loader: 'less-loader',
      },
    ],
},

修改后:

{
  test: /\.less$/,
  use: ['thread-loader', 'vue-style-loader', 'css-loader', 'less-loader'],
},

控制台输出

移除间隔 10 秒输出及其他冗余的控制台输出信息

// if (!flage.view) {
//   console.log(chalk.red('  ️!!!警告!!!'))
//   console.log(chalk.red('  ️你没有指定view参数'))
// }

// setInterval(function () {
//   logRunningInfo()
// }, 10000)

引入项目信息,基于 chalk 进行自定义输出。

一个前端项目的 webpack 调优记录

文件缓存

性能提升 90% 的配置,在 webpack.base.conf.js 中添加以下内容:

cache: { type: 'filesystem' }

分别进行若干次打包测试:

优化前:

打包次数打包时间启动时间
第一次00:03:05153.399s
第二次00:02:57129.427s
第三次00:03:06126.139s

平均打包耗时:00:03:02,平均启动耗时:136.321s

优化后:

打包次数打包时间启动时间
第一次00:03:19128.76s
第二次00:00:129.816s
第三次00:00:1310.298s

平均打包耗时:00:01:14,平均启动耗时:49.625s

jenkins 打包测试

优化前:

一个前端项目的 webpack 调优记录

优化后:

一个前端项目的 webpack 调优记录

单次构建对比,启动和打包效率提升 10 倍!

PS:文件缓存结果存储在 node_module 文件夹下,会占用约 2 个G的磁盘空间(取决于项目规模)。

一个前端项目的 webpack 调优记录

总结

webpack v4 升级至 v5 后,可以使用 v5 更多更强大的新特性,为项目的后续优化提供了基础。在当前未做更多优化的情况下,仅靠文件缓存一项配置,就给项目启动和构建带来了足够大的效率提升。