首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

加速 Webpack(1)通过多进程并行处理

加速 Webpack(1)通过多进程并行处理

通过多进程并行处理由于有大量文件需要解析和处理,构建是文件读写和计算密集型的操作,特别是当文件数量变多后,Webpack 构建慢的问题会显得严重。 运行在                Node.js 之上的 Webpack 是单线程模型的,也就是说 Webpack 需要处理的任务需要一件件挨着做,不能多个事情一起做。
文件读写和计算操作是无法避免的,那能不能让 Webpack 同一时刻处理多个任务,发挥多核 CPU 电脑的威力,以提升构建速度呢?
使用                HappyPackHappyPack 就能让 Webpack                做到上面抛出的问题,它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
接入 HappyPack 的相关代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    const path = require('path');
    const  ExtractTextPlugin =  require('extract-text-webpack-plugin');
    const  HappyPack = require('happypack');
    module.exports = {
        module: {
            rules: [
                {    test: /\.js$/,
                    // 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
                    use:['happypack/loader?id=babel'],
                    // 排除 node_modules 目录下的文件,node_modules目录下的文件都是采用的 ES5 语法,没必要再通过 Babel 去转换
                    exclude: path.resolve(__dirname, 'node_modules'),
                 },
                {
                    // 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例
                     test: /\.css$/,
                     use:ExtractTextPlugin.extract({
                        use: ['happypack/loader?id=css'],
             }),
        },
] },
    plugins: [
        new HappyPack({
            // 用唯一的标识符 id 来代表当前的HappyPack 是用来处理一类特定的文件
        id: 'babel',
            // 如何处理 .js 文件,用法和 Loader配置中一样
        loaders: ['babel-loader?cacheDirectory'],
     }),
        new HappyPack({
                id: 'css',
                    // 如何处理 .css 文件,用法和Loader 配置中一样
                loaders: ['css-loader'], }),
                new ExtractTextPlugin({
                    filename: `[name].css`,
            }),
        ],
    };




以上代码有两点重要的修改:
  • 在 Loader 配置中,所有文件的处理都交给了 happypack/loader 去处理,使用紧跟其后的 querystring                    ?id=babel 去告诉 happypack/loader 去选择哪个 HappyPack 实例去处理文件。
  • 在 Plugin 配置中,新增了两个 HappyPack 实例分别用于告诉 happypack/loader 去如何处理 .js 和                    .css 文件。选项中的 id 属性的值和上面 querystring 中的 ?id=babel 相对应,选项中的 loaders 属性和                    Loader 配置中一样。
接入 HappyPack 后,你需要给项目安装新的依赖:
npm i -D happypack
安装成功后重新执行构建,你就会看到以下由 HappyPack 输出的日志:
Happy[babel]: Version: 4.0.0-beta.5. Threads: 3
Happy[babel]: All set;                signaling webpack to proceed.Happy[css]: Version: 4.0.0-beta.5. Threads:                3Happy[css]: All set; signaling webpack to proceed.
说明你的 HappyPack 配置生效了,并且可以得知 HappyPack 分别启动了3个子进程去并行的处理任务。
在整个 Webpack 构建流程中,最耗时的流程可能就是 Loader                对文件的转换操作了,因为要转换的文件数据巨多,而且这些转换操作都只能一个个挨着处理。 HappyPack                的核心原理就是把这部分任务分解到多个进程去并行处理,从而减少了总的构建时间。
从前面的使用中可以看出所有需要通过 Loader 处理的文件都先交给了 happypack/loader 去处理,收集到了这些文件的处理权后                HappyPack 就好统一分配了。
每通过 new HappyPack() 实例化一个 HappyPack 其实就是告诉 HappyPack 核心调度器如何通过一系列 Loader                去转换一类文件,并且可以指定如何给这类转换操作分配子进程。
核心调度器的逻辑代码在主进程中,也就是运行着 Webpack                的进程中,核心调度器会把一个个任务分配给当前空闲的子进程,子进程处理完毕后把结果发送给核心调度器,它们之间的数据交换是通过进程间通信 API                实现的。
核心调度器收到来自子进程处理完毕的结果后会通知 Webpack 该文件处理完毕。
使用                ParallelUglifyPlugin在使用 Webpack 构建出用于发布到线上的代码时,都会有压缩代码这一流程。 最常见的 JavaScript 代码压缩工具是 UglifyJS,并且 Webpack 也内置了它。
用过 UglifyJS                的你一定会发现在构建用于开发环境的代码时很快就能完成,但在构建用于线上的代码时构建一直卡在一个时间点迟迟没有反应,其实卡住的这个时候就是在进行代码压缩。
由于压缩 JavaScript 代码需要先把代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理                AST,导致这个过程计算量巨大,耗时非常多。
为什么不把多进程并行处理的思想也引入到代码压缩中呢?
ParallelUglifyPlugin 就做了这个事情。 当 Webpack 有多个                JavaScript 文件需要输出和压缩时,原本会使用 UglifyJS 去一个个挨着压缩再输出, 但是 ParallelUglifyPlugin                则会开启多个子进程,把对多个文件的压缩工作分配给多个子进程去完成,每个子进程其实还是通过 UglifyJS 去压缩代码,但是变成了并行执行。 所以                ParallelUglifyPlugin 能更快的完成对多个文件的压缩工作。
使用 ParallelUglifyPlugin 也非常简单,把原来 Webpack 配置文件中内置的 UglifyJsPlugin 去掉后,再替换成                ParallelUglifyPlugin,相关代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
const path = require('path');
const  ParallelUglifyPlugin =  require('webpack-parallel-uglify-plugin');
module.exports = {
        plugins: [
            // 使用 ParallelUglifyPlugin 并行压缩输出的 JS 代码
            new ParallelUglifyPlugin({
                // 传递给 UglifyJS 的参数
                uglifyJS: {
                 },
            }),
        ],
    };




接入 ParallelUglifyPlugin 后,项目需要安装新的依赖:
npm i -D webpack-parallel-uglify-plugin
安装成功后,重新执行构建你会发现速度变快了许多。如果设置 cacheDir 开启了缓存,在之后的构建中会变的更快。
返回列表