【javascript】使用happypack和thread-loader加速构建「建议收藏」

2022-09-27 09:56:23 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

使用happypack和thread-loader加速构建

标签: webpack


为什么需要happypack和thread loader

 webpack需要处理的文件是非常多的,构建过程是一个涉及大量文件读写的过程。项目复杂起来了,文件数量变多之后,webpack构建就会特别满,而且运行在nodeJS上的webpack是单线程模型的,也就是说Webpack一个时刻只能处理一个任务,不能同时处理多个任务。

 文件读写和计算操作是无法避免的,那能不能让Webpack在同一时刻处理多个任务发挥多核CPU电脑的功能,以提升构建速度呢?

happypack

HappyPack就能让Webpack做到这一点,它将任务分解给多个子进程去并发执行,子进程处理完后再将结果发给主进程。

happypack的用法:

代码语言:javascript复制
// @file: webpack.config.js
const HappyPack = require('happypack');

exports.module = { 
   
  rules: [
    { 
   
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: ['happypack/loader'?id=babel], // 这里的id 就是定义在plugin里面HappyPack实例构造参数传入的id
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    }
  ]
};

exports.plugins = [
  // 2) create the plugin:
  new HappyPack({ 
   
    // 3) re-add the loaders you replaced above in #1:
    loaders: [ 'babel-loader?presets[]=es2015' ],
    id: 'babel'
  })
];

 创建HappyPack实例除了id/loaders【注意,一些loader的API,happypack并不支持,看这里】还有其他参数,我们列举相对重要的几个参数:

threads:

 代表开启几个子进程去编译源文件【执行当前的任务】,默认是3。

threaPool:

 代表进程共享池,多个HappyPack实例去使用同一个进程共享池中的子进程去处理任务,防止资源占用太多。

 代码长这样:

代码语言:javascript复制
// @file: webpack.config.js
const HappyPack = require('happypack');
var happyThreadPool = HappyPack.ThreadPool({ 
    size: 5 });

exports.module = { 
   
  rules: [
    { 
   
      test: /.js$/,
      // 1) replace your original list of loaders with "happypack/loader":
      // loaders: [ 'babel-loader?presets[]=es2015' ],
      use: ['happypack/loader'?id=babel], // 这里的id 就是定义在plugin里面HappyPack实例构造参数传入的id
      include: [ /* ... */ ],
      exclude: [ /* ... */ ]
    },
    { 
   
      test: /.less$/,
      use: 'happypack/loader?id=styles'
    },
  ]
};

exports.plugins = [
  // 2) create the plugin:
  new HappyPack({ 
   
    // 3) re-add the loaders you replaced above in #1:
    loaders: [ 'babel-loader?presets[]=es2015' ],
    threadPool: happyThreadPool,
    id: 'babel'
  }),
  new HappyPack({ 
   
    id: 'styles',
    threadPool: happyThreadPool,
    loaders: [ 'style-loader', 'css-loader', 'less-loader' ]
  })
];

 实际上我们做的工作就是将所有需要通过loader处理的文件,都先交给hapypack,它我们做了一个工作的调度。调度器的逻辑是在主进程中,也就是运行着webpack的node进程中。它将子任务分配给当前空闲的子进程,子进程处理完毕之后将结果返给核心调度器,它们之间的数据传输是通过进程间的通信API来实现的。


thread loader

 但是webpack4 官方提供了一个thread loader

 把这个 loader 放置在其他 loader 之前, 放置在这个 loader 之后的 loader 就会在一个单独的 worker【worker pool】 池里运行,一个worker 就是一个nodeJS 进程【node.js proces】,每个单独进程处理时间上限为600ms,各个进程的数据交换也会限制在这个时间内。

 配置长这样:

代码语言:javascript复制
module.exports = { 
   
  module: { 
   
    rules: [
      { 
   
        test: /.js$/,
        include: path.resolve("src"),
        use: [
          "thread-loader",
          // your expensive loader (e.g babel-loader)
        ]
      }
    ]
  }
}

 带有option的配置:

代码语言:javascript复制
use: [
  { 
   
    loader: "thread-loader",
    // loaders with equal options will share worker pools
    // 设置同样option的loaders会共享
    options: { 
   
      // worker的数量,默认是cpu核心数
      workers: 2,

      // 一个worker并行的job数量,默认为20
      workerParallelJobs: 50,

      // 添加额外的node js 参数
      workerNodeArgs: ['--max-old-space-size=1024'],


      // 允许重新生成一个dead work pool
      // 这个过程会降低整体编译速度
      // 开发环境应该设置为false
      poolRespawn: false,


      //空闲多少秒后,干掉work 进程
      // 默认是500ms
      // 当处于监听模式下,可以设置为无限大,让worker一直存在
      poolTimeout: 2000,

      // pool 分配给workder的job数量
      // 默认是200
      // 设置的越低效率会更低,但是job分布会更均匀
      poolParallelJobs: 50,

      // name of the pool
      // can be used to create different pools with elsewise identical options
      // pool 的名字
      //
      name: "my-pool"
    }
  },
  // your expensive loader (e.g babel-loader)
]

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/179113.html原文链接:https://javaforall.cn

0 人点赞