后台项目的webpack 优化之路

840 阅读6分钟

前言:最近接手组内的后台项目、由于历史的原因很多的配置都已经过时、冗长;当然这不是重点、重点是每次打包的时间很长、高达4分钟左右、已经严重的影响了开发效率, 本着一个程序员的素养 打算入手优化、如果内容有帮助到你的话欢迎点赞!

本地环境

项目是create-react-app脚手架进行初始化:

node:v12.7.0
webpack:4.19.1
react:^16.13.0
react-dom:^16.8.2
antd: 4.0.0

     通过上图的项目配置的antd也就知道这个项目的时间还是比较久的、里面涉及到一些自定义的组件其实在最新的antd组件库已经满足、但是由于历史的原因和优化的工作量的问题 这次没有做太多的改动。

分析工具

工欲善其事,必先利其器、在优化之前我们需要看一下到底是那些模块阻塞了打包的速度

npm i webpack-bundle-analyzer progress-bar-webpack-plugin chalk -D

在webpack.config.prod.js 引入webpack-bundle-analyzer、progress-bar-webpack-plugin、chalk

// webpack.config.prod.js 
...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const chalk = require('chalk');

...

plugins:[
    new ProgressBarPlugin({
      format: ' build [:bar] ' + chalk.green.bold(':percent') + ' (:elapsed seconds)',
      clear: false
    }),
    new BundleAnalyzerPlugin(),
]

第一次打包

打包时间:7分钟左右;

image.png

打包解析包:94MB

image.png

进行代码分块处理

由上图的依赖可视化工具可以看到很多的第三方的包没有做优化处理;然后看prod的配置采用的默认的;如下图: splitChunks

// webpack.config.prod.js 
...
splitChunks: {
  chunks: 'all',
  name: false,
},
...

更改为:

// webpack.config.prod.js 
...
splitChunks: {
  cacheGroups: {
    vendor: {   // 第三方模块
      chunks: 'all',
      name: 'vendor-common', // chunk 名称
      test: /[\\/]node_modules[\\/]/, // 匹配目录
      minChunks: 1  // 复用次数
    },
  }
},
...

执行:

npm run build

打包时间:2分钟左右;

image.png

打包解析包:7.9MB

image.png

进行split拆分优化的虽然可以合并包的引用关系、但是也会出现css的冲突的问题,如下图:

image.png

针对以上的情况通常有以下几种解决方案:

  • 其实只要运行项目的时候没有样式变形就不用管、但是要编译的时候屏蔽报错警告的话可以参考资料
  • 进行css module 配置 进行css的样式隔离。

测量构建时间

可以通过当前的插件工具分析各个阶段花费的时间、通过不同的loader和plugins进行优化处理、这里就不截图了可以参考:减少loader的查找范围、 creta-react-app配置需要找到scripts/build.js

npm i speed-measure-webpack-plugin -D
// build.js

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

...
function build(previousFileSizes) {
  ...
  let compiler = webpack(smp.wrap(config)); // 增加
  ...
} 

拆分第三方库

npm i html-webpack-tags-plugin -D

通过配置externals可以从输出的 bundle 中排除依赖、采用CDN的方式、这里推荐:猫云 国内服务器、速度比较快、资源较多。

tips:

  • 如果CDN的方式引入的react版本为16.13,那么在渲染大型项目会会出现渲染过慢的情况、建议使用17版本
  • 如果使用CDN的方式加载antd 那么请在package.json去除babel-plugin-import 、去除配置参考资料
// webpack.config.prod.js 
... 
const HtmlWebpackTagsPlugin = require('html-webpack-tags-plugin');
...
externals:{
    "xlsx":'XLSX',
    "mathjs":"math",
    "react":"React",
    "react-dom":"ReactDOM",
    "moment":"moment",
    "antd":"antd",
},
piugins:[
    new HtmlWebpackTagsPlugin({
      scripts: [
       
        { 
          path: "https://cdn.bootcdn.net/ajax/libs/react/17.0.0/umd/react.production.min.js", 
          publicPath: false,
          append:false,
          attributes:{
            crossorigin:"anonymous"
          }
        },
        { 
          path: "https://cdn.bootcdn.net/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js", 
          publicPath: false,
          append:false,
          attributes:{
            crossorigin:"anonymous"
          }
        },
        ...
      ]
    }),
]
...

执行:

npm run build

打包解析包:5.25MB

image.png

配置DllPlugin

   由上图可以看到有些三方依赖是没拆分出来的,是因为单纯的CDN可能不满足组件的拆分条件、可以使用webpack自带的DllPlugin进行动态链接库、利用空间换取时间、把复用性较高的第三方模块打包到动态链接库中,在不升级这些库的情况下,动态库不需要重新打包,每次构建只重新打包业务代码。

tips:

  • 不用版本的webpack配置的webpack-cli版本不一致、比如:webpack@4.19.1对应的webpack-cli@4.2.0

新建 webpack.config.dll.js

/*
 * @Author: DllPlugin 进行全部的打包
 * @Date: 2021-08-24 16:06:20
 * @LastEditTime: 2021-09-06 20:16:53
 */
const webpack = require('webpack');
const path = require('path');

module.exports = {
  mode:"production",
  entry: {
     common: ['react-quill','echarts','@ant-design/compatible','@ant-design/icons']
  },
  output: {
    filename: '[name].dll.js',
    path: path.join(__dirname, '../public/dll'),
    libraryTarget: 'var',
    library: '_dll_[name]_[hash]'
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '../public/dll', '[name].manifest.json'),
      name: '_dll_[name]_[hash]'
    })
  ],
  performance: {
    hints: false,
  }
};

配置命令:

// package.json
"dll": "webpack --config config/webpack.config.dll.js",
"build": "npm run dll &&  scripts/build.js",

修改 webpack.config.prod.js

// webpack.config.prod.js 
plugins:[
 new HtmlWebpackTagsPlugin({
  { path: 'dll/common.dll.js'},
    ...
 })
]

针对antd主题变量的替换

项目中有很多之前需求需要的自定义主题,之前采用的方式是直接进行less的变量覆盖,目前为了优化已经换成了CDN的方式、显然是不行、可以通过配置prod的封装的getStyleLoaders函数设置less-loadermodifyVars属性进行设置,参考CDN引入antd不支持主题颜色

新建 theme.config.js

/*
 * @Author: 配置antd的配置主题的颜色【针对CDN】
 * @Date: 2021-09-03 16:16:28
 * @LastEditTime: 2021-09-03 17:40:23
 */

const theme = {
  'primary-color': '#845f3f', 
  'link-color': '#845f3f',
  'success-color': '#52c41a',
  'warning-color': '#faad14',
  'error-color': '#f5222d',
  'font-size-base': '14px',
  'heading-color': 'rgba(0, 0, 0, .85)',
  'text-color': 'rgba(0, 0, 0, .65)',
  'text-color-secondary': "rgba(0, 0, 0, .45)",
  'disabled-color': 'rgba(0, 0, 0, .25)',
  'border-radius-base': '4px',
  'border-color-base': '#d9d9d9',
  'box-shadow-base': '0 2px 8px rgba(0, 0, 0, .15)',
  'radio-button-hover-color':"#1890ff",
  "radio-dot-color":"#1890ff"
}

module.exports =  theme

修改 webpack.config.prod.js

// webpack.config.prod.js 
const theme = require('./theme.config')   // 定制主题
...
const getStyleLoaders = (cssOptions, preProcessor) => {
....

 if( preProcessor ) {
    if(preProcessor === 'less-loader') {
      loaders.push({
        loader: require.resolve(preProcessor),
        options: {
          sourceMap: shouldUseSourceMap,
          modifyVars: theme,
        },
      });
    }else if( preProcessor === 'sass-loader' ) {
      loaders.push({
        loader: require.resolve(preProcessor),
        options: {
          sourceMap: shouldUseSourceMap,
        },
      });
    }
  }

};


开发环境优化

首次构建时间没有太大变化,但是第二次开始,构建时间大约可以节约 80%。

npm i hard-source-webpack-plugin -D

其他

  • 对lodash 进行了按需加载
  • 增加了less modules配置、
  • 增加了可视化进度条webpackbar

总结:

这次的优化最后的截止打包的时间为30s左右、Parsed:5.25MB、Gzipped:1.4MB、造成的原因如下:

  • @ant-design 、echarts 没有抽离出来、无法引用CDN的方式 只能用dll的方式进行缓存
  • 在文件目录的src目前没有进行splitChunks配置、但是由于工作量太大、下期处理
  • 未升级antd组件库的版本、进行icon的体积减小
  • 未升级webpack5、升级之后可能打包的速度会提升一个新的台阶

以上就是这次整个打包优化资料、能帮助大家最好、如有指教感激不尽。

参考资料