Parcel v2.8.0

我们很高兴地宣布 Parcel v2.8.0 发布!此版本包含一个全新的打包算法,该算法改进了自动代码拆分,大幅提升了大型项目的构建性能,并修复了许多错误。它还包含了对 HMR 更新的重大性能改进,以及树摇动更改,我们已经看到它将捆绑包大小减少了高达 50%。

新的打包算法

#

自从我们最初发布 v2 以来,Parcel 一直支持 自动代码拆分,它可以对应用程序多个部分(例如页面、动态导入等)之间的共享模块进行重复数据删除。这允许像 React 或设计系统这样的常用依赖项独立于应用程序代码进行缓存,从而减少在页面之间导航时必须加载的代码量。由于它是自动的,因此开发人员无需手动配置或更新它,从而在您进行更改时保持应用程序的最佳状态。

我们最初的实现对于中小型项目效果很好,但在大型项目中遇到了可扩展性问题。该算法涉及许多嵌套的图遍历(二次时间复杂度),并且经常最终执行了后来被撤销的工作。此外,该实现有一些错误,有时会导致不必要的重复,甚至丢失模块。

Atlassian 团队贡献了一个新的打包算法,解决了这些问题,显著提高了构建时间和运行时性能。它采用了一种与之前实现不同的方法:它不是最初将所有资产根据手动代码拆分点(例如动态导入)放入捆绑包中,然后在之后删除重复项,而是从一个没有重复项的图开始(每个资产只在一个捆绑包中)。然后,它根据并行请求限制和最小捆绑包大小要求等约束条件,根据需要组合捆绑包。它还通过预先计算更多信息并删除嵌套的图遍历来降低时间复杂度。

这会导致更小的捆绑包和更快的构建速度。对于一个包含超过 60,000 个资产的非常大的真实世界项目,总构建时间从超过 25 分钟减少到 9 分钟(快 2.7 倍)。整个项目的总捆绑包大小从 952 MB 减少到 370 MB(小 2.5 倍)。相比之下,使用 webpack 构建相同的应用程序需要超过 45 分钟。

我们一直在研究这个新的打包算法很长时间了,我们很高兴终于在本次发布中将其设为默认值。非常感谢 Atlassian 团队贡献了这项改进!

HMR 重建性能

#

除了提高打包性能之外,我们还一直在努力使增量重建和 HMR 更新更快。此版本包含三个新功能:增量打包、单线程编译和更早的 HMR 更新。

一些工具在开发中完全避免打包,而是利用浏览器中的 ESM 来单独加载每个模块。这意味着当文件发生更改时,只需要转换该文件,而不是重新计算整个捆绑包。但是,对于包含许多模块的大型项目,这种方法意味着浏览器必须在页面加载时进行数百甚至数千次级联 HTTP 请求。此外,在执行 HMR 更新时,浏览器必须进行网络请求以重新加载每个更新的文件。由于无法在 ESM 模块注册表中使模块失效,因此必须手动更新依赖模块。

Parcel 已经有一个仅限开发的打包器,它比生产打包器的工作量少得多(例如,没有树摇动),但对于大型应用程序,上面描述的打包算法仍然可能是瓶颈。但是,大多数代码更改都相当简单——它们只影响单个文件,而不会添加或删除任何依赖项。在这些情况下,重新打包是不必要的,Parcel 现在可以简单地更新资产,而无需重新运行整个打包算法。此外,Parcel 现在在仅更改单个文件时在主线程上进行编译和打包,以避免将捆绑包图序列化以在工作线程之间发送的成本。

这种增量打包可以产生巨大的差异——例如,上面描述的大型项目的重建时间从 40 秒减少到 4 秒(快 10 倍)!

此外,Parcel 现在在打包捆绑包完成之前通过 websocket 向浏览器发送 HMR 更新。我们自定义的仅限开发的模块格式使我们能够重新评估已更改的模块,并在没有额外的网络请求的情况下将它们替换。这实际上意味着 HMR 更新所需的工量与未打包时相同,随着更改大小而不是项目大小而扩展,并避免了页面加载期间的网络瀑布。

我们一直在对我们的端到端 HMR 更新性能与其他工具进行基准测试。以下结果显示了从保存文件到在浏览器中看到更新的时间,用于包含 1000 个组件的 React 应用程序

Vite Turbopack Parcel
293.5ms 274.8ms 88.6ms
叶子 143.8ms 57ms 37.4ms

请参阅 此仓库,了解完整的基准测试源代码和结果。

树摇动改进

#

此版本还包含对代码拆分的树摇动的改进。以前,如果您使用了一个包含许多重新导出的索引文件的大型库,Parcel 总是将所有使用的导出放在同一个捆绑包中。例如,如果您在不同的页面或代码拆分点(例如动态导入)上使用了组件库中的不同组件,那么整个项目中所有使用的组件都将被放置到入口捆绑包中。这可能意味着在初始页面加载时加载了比必要更多的 JavaScript。

Parcel 现在将依赖项重写为指向它们的最终目标,并跟踪沿途找到的所有重新导出。这意味着 无副作用包 中的重新导出现在对代码拆分没有影响,并且每个捆绑包中只有使用的导出才会被加载。在许多应用程序中,这意味着入口捆绑包会变得更小,因为更多代码只会在需要时加载。

结果将取决于您依赖的重新导出数量和您的代码拆分设置,但到目前为止,我们在几个应用程序中看到了令人印象深刻的改进。一个非常大的应用程序的 JS 入口捆绑包减少了超过 40%,而另一个应用程序的 JS 入口减少了 25%,CSS 减少了 50%。

感谢 Niklas Mischkulnig 贡献了这项改进!

感谢!

#

Parcel v2.8.0 包含其他一些较小的功能、错误修复和改进。查看完整的 发布说明,了解更多详细信息。