rollup打包加速

起因

目前在开发一个jsonschema 渲染列表页的npm 包,采用的rollup 打包。刚开始一切安好,但最近发现打包速度越来越慢,差不多需要35s,简直无法忍受。尤其是在近期需求变多,常常被需求催促的时候,改一行代码需要等待半分钟才能看到效果,简直心态爆炸。于是决定专门抽时间优化一波。

实操

首先我们需要有一个大致的优化思路,时间优化,在计算机领域算是一个老生常谈的话题了,也有很多包治百病的套路:

  1. 减少打包文件的数量
  2. 减少不必要的执行函数
  3. 增加打包缓存,进行增量打包
  4. 由单线程变为多线程

基于这个思路,让我们来开始优化吧。首先贴一下最开始的rollup.config.js

设置external

作为一个npm lib ,确实有一些第三方依赖,应该做为peerDependencies引入,并且在打包的时候加入到external中。在我原来的配置当中,我使用了rollup-plugin-peer-deps-external插件,会自动的把peerDependencies 生成到external 配置中,无需额外配置。

在原来的peerDependencies 中,我放入了react、antd 等几个理论上一定得放入peerDependencies 的包。

而目前,为了加速打包流程,我考虑把一些可加可不加的第三方依赖加入到external 中,例如我所依赖的一个比较大的包@byted-search/jsonschema-form 等。当我新增了三个peerDependencies 后,打包时间从39.5s降低到了29.7s,收效很明显。

原理很好理解,加入到external 中的包,rollup 不会进行处理,会直接依赖外部的包。

配置babel

Babel 在打包的过程中,执行了很多耗时操作,对babel 插件的优化,应该能很好的提升打包效率。

首选我们想的的就是减少不必要的打包文件,最基本的就是设置exclude: "**/node_modules/**",不去操作node_modules 里面的文件。但我们发现,在之前的配置中我已经设置了。

这时我注意到了控制台的一行提示:

babelHelpers: ‘bundled’ option was used by default. It is recommended to configure this option explicitly, read more here: https://github.com/rollup/plugins/tree/master/packages/babel#babelhelpers

点开链接可以看到具体的介绍,大致意思是说:

Bable 插件有一个babelHelpers 的配置参数,取值为’bundled’ | ‘runtime’ | ‘inline’ | ‘external’,默认是’bundled’。

当你在开发一个应用的时候,建议使用’bundled’,会把bable 的一些helpers 函数直接打包进去; 如果你是开发lib,那么更加推荐runtime,这种方式不会打包这些helpers ,而是在开发者最终打包的时候一起打包。

最开始其实我是想让使用者用起来更加方便,所有就使用了默认值。现在看完文档,觉得文档说的也有道理,另外少打包文件,一定是能加快我的编译速度的。于是我果断改了配置为’runtime’。

另外,除了改配置,我们还需要把@babel/runtime加到dependencies中,保证开发者本地会安装@babel/runtime,然后再在rollup.config.js中手动加上一行:

external: [/@babel\/runtime/]

重新打包下,我们可以看到,打包时间从29.7s 变成了22.2s。

使用环境变量

虽然打包时间已经缩短了1/3,但是我还是无法接受。那么一些边边角角可以优化的地方,还是要优化一下。

这里主要的一个思想是,我们的开发环境下的打包和最终给到用户的打包,一定是有一些不一样的地方。对于我们的开发环境,为了效率能提升,“简陋”一些也无妨。

只打包一种格式

我们输出给用户的,一般会包含cjs,es,umd三种格式的产物,但在开发时,其实没有必要,有一种就可以了。这里我只保留了cjs。

关闭sourceMap

Rollup 的sourceMap 我没有关闭,对本地调试还是很有帮助的。不过我在查优化资料的时候,发现@rollup/plugin-commonjs这个插件会记录esm 到cjs 的sourceMap,默认是打开的。还不知道关闭后有什么影响,看github 有人推荐关闭,我也暂且先关闭了。

以上两步操作完之后,打包时间从22.2s 减少到了18.7s。

使用Cache

在优化的过程中我注意到,其实rollup --watch 打包,每次都是全量的重新打包。为什么不能像webpack 一样,进行增量打包,对上一次的打包结果进行缓存,只编译有更改的文件呢?

抱着希望去查了 rollup 的文档,虽然有cache 参数,但基本没什么用,而且还不知道如何用,Google也查不到。于是到github 的issue 列表里进行查找,得到的结论就是目前为止不支持cache,因为加入这个功能后可能会导致很多插件不能正常工作。

这真是一个悲伤的消息,我的大招没了。

大招includeDependencies

到目前为止,每次编译还需要18s,这我还是很难接受的。必须再想想办法。

经过之前的摸索和尝试,其实还是把第三方包添加到external 的收效最明显。我有个大胆的想法,可不可以在开发环境中把所有第三方依赖都加入到external 中?先动手试一试。

奇迹出现了!项目不仅能正常运行,打包时间直接由18s 减少到3.6 s。

这下我能接受了!

之前说过,rollup-plugin-peer-deps-external插件,会自动的把peerDependencies 生成到external 配置中。我隐约记得,这个插件还有一个配置,可以把dependencies 也加入到external中,当时还在想为什么还有这种需求?赶紧查看下文档,果然有一个参数:includeDependencies

peerDepsExternal({
    includeDependencies: !isProd, // speed up
}),

结尾

至此,打包时间由39.5s 缩短至3.6s,减少了91% 的编译时间,暂时心满意足了。

目前刚用rollup 不久,欢迎各位大佬给一些建议和最佳实践,贴下代码。

2 Comments

  1. process.env.NODE_ENV的NODE_ENV是如何配置的,使用的是rollup打包,可以在执行打包命令的地方设置变量值吗,我设置了不起效

Leave a Comment

邮箱地址不会被公开。 必填项已用*标注