记一次 webpack4+ 打包优化经历

因为项目过于庞大,有组内的小伙伴有人抱怨项目启动太慢啦。所以这个事得办。抓紧办。

期间考虑要不要升一下webpack5,其实webpack5在其他项目中已经升级过,对于项目的打包速度没有什么提升,只是内置了一些类似于缓存hard-source-webpack-plugin插件、file-loader等,ps: 我对webpack5的关注点在于模块联邦,实现不同项目间组件复用、微前端这些。。。

所以就拿着webpack4开搞吧。

1. 包体积

ps: 包的体积减小自然会使构建的速度有所提升

包体积分析插件 BundleAnalyzerPlugin

BundleAnalyzerPlugin配置入webpack中会自动生成打开包分析页面localhost:8888;

plugins: [
    new HtmlWebpackPlugin({ template: './index.html' }),
    // HMR
    new webpack.HotModuleReplacementPlugin(),
    // new CleanWebpackPlugin(['public']),
    new CopyWebpackPlugin([{
      from: './src/assets',
    }]),
    new MiniCssExtractPlugin({
      filename: 'vender.css',
      chunkFilename: '[name].css',
    }),
    new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /zh-cn/),
    new WebpackBar({
      color: '#0096f5',
      name: 'frontend',
    }),
    new OpenBrowserPlugin({ url: 'http://localhost:7878' }),
    new BundleAnalyzerPlugin({ analyzerHost: 'localhost' }),
  ],

启动项目的同时 会打开这样一个页面


拆包前的包体积分析

当然我们不想每次启动项目就展开包体积分析,所以我们给他一个其他的启动命令,只有运行这个启动命令时再进行包分析

"scripts": {
    "visu": "NODE_ENV=visu node script/prod-build",
},
// 运行 yarn visu的时候将node环境设为visu 并运行script文件夹下的prod-build文件

// 那么主要的逻辑就在prod-build.js文件中了

// prod-build.js主要是修改node变量、合并BundleAnalyzerPlugin和webpack的其他插件、运行webpack。
const webpack = require('webpack');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const browserConfig = require('../webpack.prod');// 拿到webpack的主要配置项

if (process.env.NODE_ENV === 'visu') { //当环境是visu的时候添加BundleAnalyzerPlugin插件
  browserConfig.plugins.push(new BundleAnalyzerPlugin({ analyzerHost: 'localhost' }));
}

// Webpack compile in a try-catch
function compile(config) {
  let compiler;
  try {
    compiler = webpack(config);
  } catch (e) {
    console.log('error');
    process.exit(1);
  }
  return compiler;
}

const clientCompiler = compile(browserConfig);// 启动webpack编译

clientCompiler.run((err) => {
  if (err) {
    console.error(err);
  }
});
// 这样就通过yarn vis能够给编译的webpack加入BundleAnalyzerPlugin
// 命令运行时自动打开包分析页面了

有了包分析,我们就可以进行包的拆分了
拆包好处太多了:打包速度快、公共包拎出来避免每次编译、按需加载、首评打开速度提升。。。

拆包
// webpack4和5都可以通过optimization的splitChunks来做
// 其实也可以用dllplugin(webpack3时代用的比较多这次就不用了,因为有更好的)
optimization: {
    splitChunks: {
      minSize: 30720, // 超过30K分包
      maxSize: 102400, // 分包最大100K超出再分包
      minChunks: 1,
      maxAsyncRequests: 6,
      maxInitialRequests: 4,
      cacheGroups: {
        'react-vendor': {
          test: module => /react/.test(module.context) || /classnames/.test(module.context) || /mobx/.test(module.context),
          priority: 4,
          reuseExistingChunk: true,
          name: 'react',
        },
        'antd-vendor': {
          test: module => (/antd?/.test(module.context)),
          priority: 3,
          reuseExistingChunk: true,
          name: 'antd',
        },
        'xlsx-vendor': {
          test: /xlsx/,
          priority: 1,
          reuseExistingChunk: true,
          name: 'xlsx',
        },
        'lodash-vendor': {
          test: /lodash/,
          priority: 2,
          reuseExistingChunk: true,
          name: 'lodash',
        },
        vendors: {
          name: 'chunk-vendors', // 优先级小于output.filename
          test: /[\\/]node_modules[\\/]/,
          priority: -10,
          reuseExistingChunk: true,
        },
        common: {
          name: 'chunk-common',
          minChunks: 2,
          priority: -20,
          reuseExistingChunk: true,
        },
      },
    },
  },

这样在包分析页就可以看到,很多的模块的公共的包被抽离了出来,且没有了大体积的文件
(在这个项目中 体积由30.2M变成了6.74M,优化到原来的四分之一多)


拆包后的包体积分析

2. 构建速度

构建速度提升的点可太多了,代码写质量都会有影响,在webpack中构建的速度很受打包文件数量和编译的loader限制。
要提升构建的速度,我们首先得知道当前webpack打包的时常是多少,这里用到的是speed-measure-webpack-plugin插件

打包速度分析(speed-measure-webpack-plugin)
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
const smp = new SpeedMeasurePlugin();
module.exports = smp.wrap({ // smp.wrap()包一下webpack的配置即可
  entry: ['src/index.js'],
  output: {
    path: resolve('public'),
    filename: 'vender.js',
    chunkFilename: '[name].js',
    publicPath: '/',
  },
  resolve: {
    alias: {
      src: resolve('src'),
      assets: resolve('src/assets'),
      components: resolve('src/components'),
      style: resolve('src/static/style'),
    },
  },
。。。。
打包速度优化前

以上这个日志可能被其他webpack日志顶没,最好在命令行查看,别在编辑器中找

打包速度优化

打包速度优化主要用的是开启多进程、开启缓存功能

  • 开启多进程用的是thread-loader(happy-pack插件也可以用,但是已经不再维护了)
const threadLoader = require('thread-loader');

const jsWorkerPool = {
  // options
  // 产生的 worker 的数量,默认是 (cpu 核心数 - 1)
  // 当 require('os').cpus() 是 undefined 时,则为 1
  workers: 2,
  // 闲置时定时删除 worker 进程
  // 默认为 500ms
  // 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
  poolTimeout: 2000,
};
const cssWorkerPool = {
  // 一个 worker 进程中并行执行工作的数量
  // 默认为 20
  workerParallelJobs: 2,
  poolTimeout: 2000,
};
// 可以通过预热 worker 池(worker pool)来防止启动 worker 时的高延时
threadLoader.warmup(jsWorkerPool, ['babel-loader']);// js文件的预热
threadLoader.warmup(cssWorkerPool, ['css-loader', 'sass-loader']);// css文件的预热


module.exports = smp.wrap({
  module: {
    rules: [
      {
        test: /\.(js)$/,
        exclude: /(node_modules)/,
        use: [
          {
            loader: 'thread-loader',// 开启多个work,使用预热的配置
            options: jsWorkerPool,
          },
          {
            loader: 'babel-loader',
            options: {
              babelrc: true,
            },
          },
        ],
      },
      {
        test: /\.(scss|css)$/,
        use: [
          'css-hot-loader',
          MiniCssExtractPlugin.loader,
          {
            loader: 'thread-loader',// 开启多个work,使用预热的配置
            options: cssWorkerPool,
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 1,
            },
          },
          'sass-loader',
        ],
      },
    ......
  • 开启缓存,加快二次启动速度
    webpack 自带cache缓存,但是有更牛的hard-source-webpack-plugin
    hard-source-webpack-plugin 为模块提供中间缓存步骤(首次加载很慢,但以后的构建很快
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');

plugins: [
    new HardSourceWebpackPlugin(),
],

我们来看下此时的打包速度


image.png

还有其他的一些优化类似于loader的exclude/include的使用、extends的合理使用、alias的使用。。。。巴拉巴拉的。。。就不多赘述了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,227评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,755评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,899评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,257评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,617评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,757评论 1 221
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,982评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,715评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,454评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,666评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,148评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,512评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,156评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,112评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,896评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,809评论 2 279
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,691评论 2 272

推荐阅读更多精彩内容

  • 随着项目的增大,webpack的打包速度已成前端工程师的“不可承受之重”。最近对团队内某项目的打包速度进行了一些优...
    jjjkkkhhhggg阅读 6,100评论 0 0
  • 写在前面 在现在前端工程化的大背景下,webpack成为了最常用的打包工具之一,有一社区或者优秀团队,也都以Web...
    喜剧之王爱创作阅读 1,610评论 0 10
  • 最近给项目进行webpack优化,尝试过几乎所有方法,一共26条,列举在此。 优化webpack,首先明确优化目标...
    seaasun阅读 2,106评论 0 4
  • 安装 五大核心概念 entry:打包入口,支持多入口打包output:输出,可以配置输入路径,文件名等loader...
    瓢鳍小虾虎阅读 148评论 0 0
  • 一、webpack简介 1.1 webpack是什么 1.2 webpack五个核心概念 1.2.1 Entry ...
    Liffery_cxy阅读 558评论 1 0