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 在更新根组件时比 Turbopack 快 68%,比 Vite 快 70%。
- Parcel 在更新叶组件时比 Turbopack 快 34%,比 Vite 快 74%。
请参见此仓库以获取完整的基准测试源代码和结果。
树摇改进
#此版本还包括代码拆分的树摇改进。以前,如果您使用包含带有多个重新导出的索引文件的大型库,Parcel 总是将所有使用的导出放在同一个捆绑包中。例如,如果您在不同的页面或代码拆分点(例如动态导入)上使用组件库的不同组件,则整个项目中使用的所有组件都将放入入口捆绑包中。这可能意味着在初始页面加载时加载比必要更多的 JavaScript。
Parcel 现在重写依赖项以指向其最终目的地,跟随沿途找到的所有重新导出。这意味着无副作用包中的重新导出现在对代码拆分没有影响,并且只加载每个捆绑包中使用的导出。在许多应用程序中,这意味着入口捆绑包将变得更小,因为更多代码只在需要时才加载。
结果将取决于您依赖的重新导出数量和代码拆分设置,但到目前为止,我们在几个应用程序中看到了一些令人印象深刻的改进。一个非常大的应用看到 JS 入口捆绑包减小了超过 40%,而另一个应用的 JS 入口减小了 25%,CSS 减小了 50%。
感谢 Niklas Mischkulnig 贡献了这个改进!
感谢!
#Parcel v2.8.0 包括几个其他较小的功能、错误修复和改进。查看完整的发行说明以获取更多详细信息。