Parcel 2 beta 3
Parcel 团队很高兴发布 Parcel 2 beta 3!此版本包含我们用 Rust 从头开始重写的 JavaScript 编译器,它将整体构建性能提高了 10 倍。此外,本文还将介绍自上次更新以来我们对 Parcel 所做的一些其他改进,以及我们发布稳定版 Parcel 2 的路线图。
用 Rust 编写的速度提升 10 倍的 JavaScript 编译器 🚀
#在过去几个月里,我们一直在努力用 Rust 重写我们的 JavaScript 编译器!Parcel 的 JavaScript 编译器负责检测代码中的依赖项(如 import
语句和 new Worker()
调用)、内联 process.env
变量和其他 Node 全局变量,以及执行范围提升。
此外,Parcel 会根据您配置的 browserslist
目标自动转译您的源代码,以及 JSX 和 TypeScript 等非标准语法,以及 React Fast Refresh 等开发功能。
以前,所有这些都是用 JavaScript 在 Babel AST 之上实现的。虽然我们已经做出了巨大进步优化它,但 JavaScript 编译仍然是 Parcel 最慢的部分。特别是,将大型 JavaScript AST 序列化以在线程之间发送非常慢,这些大型对象给 JavaScript 垃圾收集器带来了很大压力。此外,JavaScript 代码每次运行时都必须由引擎编译,这意味着启动速度很慢。虽然提高算法复杂度将导致性能改进,无论语言如何,但这只能让你走这么远。

Parcel 的新 JavaScript 转换器是用 Rust 在 SWC 编译器之上编写的。SWC 提供 JavaScript 解析和代码生成,以及构建超快 AST 转换的坚实基础。Rust 提供可预测的性能、即时启动时间以及优化到硬件级别的能力。
此外,范围提升链接器现在只对字符串而不是 AST 进行操作,这也极大地提高了性能,因为我们避免了序列化和反序列化这些大型对象。这也允许代码生成在所有文件上并行执行,而不是一次对整个捆绑包执行。
总的来说,这将构建性能提高了 10 倍!
在 ESBuild 基准测试中,Parcel 现在在没有 Terser 的情况下快了 10 倍,在启用缩小功能的情况下快了 3 倍。

转译性能
#此外,SWC 在设置 browserslist
时默认替换 Babel 用于转译,以及用于编译 JSX 和 TypeScript,以及 React Fast Refresh。SWC 比 Babel 快 20 倍,因此此更改也应该显着提高整体性能。
虽然 SWC 是默认的,但请放心,Babel 仍然受支持。如果您在项目中拥有自定义 Babel 配置,它仍然会自动使用。这意味着自定义 Babel 插件(例如 CSS-in-JS 转换、Babel 宏等)将继续开箱即用。范围提升、依赖项收集以及之前内置于 Parcel 的所有其他内容现在将在 Rust 中发生,但这应该是完全透明的。
然而,这确实打开了进一步提高构建性能的可能性。您现在可以从 .babelrc
中删除 @babel/preset-env
、@babel/preset-react
和 @babel/preset-typescript
,它们将由 SWC 自动处理。这可以显着提高您的构建性能。如果您有其他自定义 Babel 插件,您可以将它们保留在您的 Babel 配置中。如果没有,您可以完全删除您的 Babel 配置。我们可能会在将来添加一个警告来帮助您进行此迁移。
范围提升改进
#除了性能之外,我们还遇到了旧的范围提升实现的一些问题,这些问题促使我们重新编写。特别是,包括 Parcel 在内的几个 JavaScript 捆绑器在范围提升和代码拆分一起使用时存在错误。
范围提升是将多个 JavaScript 模块组合到一个范围内的过程。这使得死代码消除(也称为树形抖动)更加有效,并通过使跨模块引用成为静态引用而不是动态属性查找来提高运行时性能。
当将多个模块提升到同一个范围而不是将每个模块包装在单独的函数中时,很难确保这些模块在跨捆绑包引用时始终按正确的顺序执行。
此外,有时为了避免生成许多非常小的输出文件并增加加载页面所需的 HTTP 请求数量,在多个捆绑包之间重复使用小模块。以前,这会导致模块执行多次,这可能会破坏许多东西,包括副作用(例如,修改 DOM)和单例模式。
为了解决这些问题,有必要从头开始重新思考我们的范围提升编译器的工作方式。结果是范围提升的混合体,我们可以在其中提升,但在需要时回退到将模块包装在具有全局模块注册表的 CJS 风格函数中。这确保了在捆绑包之间引用的模块按正确的顺序执行,并且重复的模块只执行一次。
如果您想了解更多关于我们的范围提升实现的工作原理,请查看设计文档,其中详细介绍了所有这些主题。
树形抖动动态导入
#与我们的范围提升实现相关的另一个功能是支持树形抖动动态 import()
。Parcel 可以检测到动态导入的哪些属性被访问,并从未使用的解析模块中排除导出。这适用于 promise 链、async/await、解构和静态对象属性访问。如果任何内容以非静态方式访问,例如计算属性,则将包含所有导出。

树形抖动 CSS 模块
#我们现在还支持树形抖动 CSS 模块。当您在 JavaScript 中导入 CSS 模块时,Parcel 会跟踪哪些类被使用,并自动从编译的 CSS 文件中排除未使用的选择器。此外,类名现在会在编译的 JavaScript 中自动内联,而不是存储在一个大型对象映射中。这应该有助于减少 CSS 和 JS 输出的捆绑包大小!

延迟开发构建
#在开发中,等待整个应用程序构建完成才能启动开发服务器可能会令人沮丧。当处理具有许多页面的大型应用程序时尤其如此。如果您只在一个功能上工作,为什么需要等待所有其他功能构建,除非您实际导航到它们?
Parcel 现在支持在使用开发服务器时使用 --lazy
CLI 标志。启用后,Parcel 只构建按需请求的文件,这可以显着减少开发构建时间。服务器会立即启动,当您第一次导航到页面时,Parcel 只构建该页面所需的必要文件。当您导航到另一个页面时,该页面将按需构建。如果您导航回之前构建的页面,它会立即加载。
这也适用于动态 import()
,而不仅仅是完全独立的页面。因此,如果您有一个页面具有动态加载的功能,该功能将不会构建,直到它被激活。Parcel 足够聪明,可以立即构建所有请求文件的依赖项,而无需等待它们也被请求。如果您有一些与 JavaScript 相关的 CSS 或一些引用的图像,它们将一起构建——没有网络瀑布!
当然,权衡是页面加载和动态导入在第一次加载时可能会稍微慢一些。但是,使用 Parcel 的磁盘缓存,这应该只发生一次。即使您重新启动 Parcel,也不需要重新构建未更改的文件。
缓存可靠性
#说到缓存,我们一直在努力的另一个领域是缓存可靠性。我们希望用户信任缓存,因此我们需要确保所有可能使缓存失效的东西实际上都使缓存失效。这比听起来要难得多。现代 JavaScript 构建工具有很多输入需要跟踪——磁盘上的文件、配置、环境变量、用于编译代码的开发依赖项等等。当这些中的任何一个发生变化时,Parcel 需要使缓存失效并重新计算输出。
Parcel 在一个图中跟踪所有这些输入。我们的文件观察器 监视磁盘上的更改,并使与更改的文件连接的任何请求失效。当您重新启动 Parcel 时也会发生这种情况。我们的观察器与操作系统级 API 集成,以快速确定自上次运行 Parcel 以来哪些文件发生了更改,这意味着重新启动 Parcel 几乎与使用观察模式一样快!
开发依赖项 HMR
#所有这些关于缓存失效的工作的一个附带好处是,观察模式也受益。我们实现的一个很酷的功能是Parcel 插件和其他构建依赖项的 HMR。当您对插件的源代码进行更改时,我们会就地重新加载插件并重新构建它之前编译过的任何文件。这使得在插件上工作并立即看到您的更改变得非常快——无需重新启动 Parcel。
它也适用于 Babel 插件、PostCSS 插件以及构建中涉及的任何其他开发依赖项。您甚至可以在 node_modules
中编辑插件,Parcel 会自动重新编译。当您需要调试构建管道中的某些内容或使用 patch-package 等工具时,这很有用。
更少的依赖项
#Parcel 开箱即用地支持许多不同的语言和工具,这使得入门非常容易。但这样做的一个缺点是,安装 Parcel 包含许多您可能不会使用的依赖项。这不仅会占用磁盘空间和网络带宽,而且还会增加您需要维护和审计的依赖项。
我们希望减少 Parcel 的依赖项,同时仍然保持使用起来非常简单。为此,我们现在默认只安装必要的插件,并根据需要自动将其他插件安装到您的项目中。
默认情况下,我们包括对 HTML、CSS 和 JavaScript 等标准 Web 语言的支持。但是,只要您包含 SASS 文件、Vue、Elm、CoffeeScript 或 Parcel 识别的任何其他文件类型,我们就会自动将必要的插件和所有对等依赖项安装到您的项目中。这使 Parcel 非常易于使用(零配置),但也减少了项目中的依赖项数量。
路线图
#Parcel 2 已经开发了几年了,我们并没有一直很好地更新社区关于我们发布稳定版的路线图的进展情况。因此,本节是对我们进展情况的更新。
Beta 3 很可能将是我们第一个发布候选版本之前的最后一个测试版,我们希望它将在大约一个月内发布。对于第一个 rc,我们正在处理以下项目
- 改进打包和优化的缓存失效
- 确保缓存可在机器或不同文件路径之间移植(例如在 CI 中)
- 改进的自动差分捆绑支持(模块/nomodule)
- API 一致性
在 rc 之后,公共 API 将被冻结,我们将专注于错误修复和文档。这将需要大约一个月的时间。准备就绪后,我们将发布 2.0!
在这一点上,捆绑器、运行时和验证器的插件 API 很可能在 Parcel 2.0 中被标记为实验性。这意味着这些功能不会遵循 semver,我们将在初始稳定版 Parcel 2 发布后继续对其进行迭代。此外,我们还计划在 2.0 之后发布许多其他功能和改进,包括进一步的性能优化。
谢谢!
#一如既往,感谢您试用我们的测试版并提供有关 GitHub 的反馈。您也可以向我们的 开放集体 捐款,这将有助于支持我们的贡献者。