React打包构建速度优化 之 多进程打包 O(∩_∩)O~~

1,422 阅读3分钟

最近公司的项目越来越大,每次打包构建一次都得50多秒将近1分钟,着实是让人头疼啊,就不得不做一些性能上面的优化了,做性能优化之前我们要先了解到到底是什么原因导致的打包构建速度如此慢,对症下药嘛。speed-measure-webpack-plugin这个插件可以看出打包过程中每一个阶段都用了多少时间。

npm i speed-measure-webpack-plugin --save-dev

这个就是安装完插件的效果图每次构建的时候都会显示每个阶段都用了多久,loader,plugin占据了我们大部分打包时间,我们就开始着手医治一下

注意点:速度上来之后要把这个插件拿掉,因为他只在首次打包构建时有效,如果在编码保存之后会出问题

image.png

第一步--配置webpack 来监测构建时每个阶段的时间

只需将插件引进来然后new他的实例,将我们的webpack配置项包起来,然后重新启动项目就OK了

const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
module.exports = spm.wrap({
    、、、
})

第二部--就要引入我们的终极武器 thread-loader

为啥我们要多进程打包呢,在webpack构建过程中,我们需要使用Loader对js,css,图片,字体等文件做转换操作,并且转换的文件数据量也是非常大的,且这些转换操作不能并发处理文件,而是需要一个个文件进行处理,我们需要的是将这部分任务分解到多个子进程中去并行处理,子进程处理完成后把结果发送到主进程中,从而减少总的构建时间。我们就用到了今天的主角thread-loader这个是官方推荐的

安装

npm install --save-dev thread-loader

使用

把这个 loader 放置在其他 loader 之前, 放置在这个 loader 之后的 loader 就会在一个单独的 worker 池(worker pool)中运行

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

  • 这些 loader 不能产生新的文件。
  • 这些 loader 不能使用定制的 loader API(也就是说,通过插件)。
  • 这些 loader 无法获取 webpack 的选项设置。

每个 worker 都是一个单独的有 600ms 限制的 node.js 进程。同时跨进程的数据交换也会被限制。

注意:请仅在耗时的 loader 上使用,并且不要放在style-loader之前使用

module.exports = spm.wrap({
    module: {
     rules: [
      {
        test: /\.js$/,
        exclude: /node_modules[/\\](?!caoh5-|@qts)/,
        use: [
          'thread-loader',
          'babel-loader'
        ]
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          'thread-loader',
          { loader: 'css-loader', options: { modules: false } },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'postcss-preset-env',
                    'autoprefixer',
                    {
                      // 其他选项
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
     ]
    }
})

预热

可以通过预热 worker 池(worker pool)来防止启动 worker 时的高延时。

这会启动池(pool)内最大数量的 worker 并把指定的模块载入 node.js 的模块缓存中。

更多thread-loader前往 webpack.html.cn/loaders/thr…

const threadLoader = require('thread-loader');
const jsWorkerPool = {
  // options
  
  // 产生的 worker 的数量,默认是 (cpu 核心数 - 1)
  // 当 require('os').cpus() 是 undefined 时,则为 1
  workers: 3,
  
  // 闲置时定时删除 worker 进程
  // 默认为 500ms
  // 可以设置为无穷大, 这样在监视模式(--watch)下可以保持 worker 持续存在
  poolTimeout: 2000
};

const cssWorkerPool = {
  // 一个 worker 进程中并行执行工作的数量
  // 默认为 20
  workerParallelJobs: 20,
  poolTimeout: 2000
};

threadLoader.warmup(jsWorkerPool, ['babel-loader']);
threadLoader.warmup(cssWorkerPool, ['css-loader', 'postcss-loader']);

module.exports = spm.wrap({
    module: {
     rules: [
      {
        test: /\.js$/,
        exclude: /node_modules[/\\](?!caoh5-|@qts)/,
        // use: ['happypack/loader?id=js'],
        use: [
          {
            loader: 'thread-loader',
            options: jsWorkerPool
          },
          'babel-loader'
        ]
      },
      {
        test: /\.css$/,
        use: [
          'style-loader',
          {
            loader: 'thread-loader',
            options: cssWorkerPool
          },
          { loader: 'css-loader', options: { modules: false } },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                plugins: [
                  [
                    'postcss-preset-env',
                    'autoprefixer',
                    {
                      // 其他选项
                    },
                  ],
                ],
              },
            },
          },
        ],
      },
     ]
    }
})

到这里再次打包构建的时候速度就很快了,就没有在做其他的优化点。等之后项目再大点在进一步优化吧。希望本文章能够帮助小伙伴们。

每天进步一点,理想终将实现。

祝大家前程似锦