如何让webpack打包的速度提升50%?

11,211 阅读2分钟

随着前端应用包含的模块数量日益增长,代码打包的耗时也越来越长。公司很多项目打包耗时超过了10秒,对于一般人来说超过10秒的等待是比较难受的,虽然后续增量编辑的速度很快。于是我想结合实际开发环境提升一下首次打包的速度。

1. 实际开发环境

我碰到大多数处于维护状态的网站都有一下几个特性:

  • 模块数量庞大
  • 模块中主要分为js模块和css模块,并且less模块最后使用extract-text-webpack-plugin打包出单独的css文件
  • webpack入口文件包含了js和less,所以每次打包都需要处理js和less模块
  • 许多需求只涉及到js模块的修改,并不涉及样式修改。反之亦然。

2. 优化思路

既然许多情况下编译less模块不是必须的,那在这些情况下单独编译js模块就能大幅提升webpack的性能。毕竟less的编译、以及css的抽出都非常消耗时间。

3. 优化步骤

优化包含以下两步:

  • 区分编译目标,单独编译js? 还是单独编辑css? 还是js+css?
  • 入口文件分离js和css

3.1 区分编译目标

这一步比较简单,我们需要使用cross-env这个插件,例如下面两条编译命令区分了编译js和编译js+css。

{
	"scripts": {
	    "build:js": "cross-env ctarget=all webpack",
	    "biuld:js+css": "cross-env ctarget=js webpack"
  }
}

这样我们就可以在webpack配置文件中通过process.env.ctarget区分当前编译目标了。

3.2 分离js和css

这一步需要通过webpack的loader来实现,可以使用现有的轮子string-replace-loader

这个loader可以在编译阶段修改代码,并且可以使用正则表达式进行替换。可以使用它来加载js文件,然后删除部分代码。下面的例子的作用是删除js文件中所有的less代码导入。

{
	module: {
		rules: [
			{
            test: /.js$/,
            use: (function(){
                var list = ['这里可以加上其他需要的loader']; 
                // 更具编译目标删除less的导入
                if (process.env.ctarget === 'js') {
                    list.push({
                        loader: 'string-replace-loader',
                        options: {
                            search: '^.+?require\\(.+(\\.less).+$',
                            replace: '',
                            flags: 'm'
                        }
                    })
                }
                return list;
            })()
        }
		]
	}
}

这里在使用string-replace-loader一定要加上flags: 'm',否则无法进行多行匹配。

如果要单独打包css我们可以写一个和string-replace-loader作用相反的loader,只保留样式部分而删除其他js代码。

4. 效果

经过实际测试,这个优化可以节省50%的时间。当然具体到每一个项目还要看js和css模块数量的比例。