本文由 简悦 SimpRead转码, 原文地址 www.callstack.com
如果 Metro 会降低应用程序的运行速度,请使用其他高性能捆绑包优化应用程序的 JavaScript 捆绑包......。
以下文章是React Native 优化终极指南的一部分,介绍了如何使用不同的捆绑程序(如 Re.Pack、react-native-esbuild 和 rnx-kit)优化 React Native 应用程序的性能。
为什么这很重要?
React Native 应用程序的逻辑主要位于 JavaScript 代码中,而 JavaScript 代码在 JavaScript 引擎(JavaScriptCore 或 Hermes)中运行。但是,在将 JavaScript 代码加载到应用程序之前,应该对其进行捆绑,通常是捆绑到一个 JS 文件中,有时也可以捆绑到多个文件中。React Native 提供了一个用于捆绑 JavaScript 代码的内置工具,名为 Metro。但有时,最终捆绑的代码会变得过大,这就是性能问题的起因。
在以《React Native 优化终极指南》为基础的其他博文中,我们讨论了与通过了解 React Native 实现细节来提高性能有关的以下主题:
请务必稍后查看。现在,让我们进入优化 React Native 应用程序 JavaScript 捆绑程序的主题。
使用替代捆绑程序优化性能
Metro 会接收入口文件和各种选项,然后返回给您一个包含所有代码及其依赖项的 JavaScript 文件,也称为 JavaScript 捆绑程序。根据官方文档,Metro 可使用本地缓存的转换模块,加快开箱即用的构建速度。
Metro 以配置性换取性能,而 Webpack 等其他捆绑包则相反。因此,当你的项目需要自定义加载器时,请使用 symlinks 或成熟的 Webpack 配置来捆绑 JavaScript 代码并拆分应用逻辑。
React Native 应用程序中可以使用一些替代捆绑程序,它们提供了更多配置功能。在本文中,我们将仔细研究 Re.Pack、react-native-esbuild 和 rnx-kit,并考虑它们的优势和局限性。
Re.Pack
Re.Pack是一个基于 Webpack 的工具包,用于构建 React Native 应用程序,完全支持 Webpack 生态系统的加载器、插件,并支持 symlinks、别名、代码拆分 等各种功能。它是 Haul 的继任者,Haul 有着类似的功能,但在权衡利弊和开发人员体验方面却有着不同的平衡。顺便说一句,我们可以自豪地说,Re.Pack 是由我们的React Native 开发公司为您带来的--我们尽了一切努力使它尽可能有价值且对开发人员友好。
在 React Native 项目中使用 Re-Pack 的好处
Webpack 的生态系统部分对许多开发人员来说至关重要,因为它是网络上最流行的捆绑程序,加载器和插件背后的社区是它的主要优势。得益于这种可插拔性,它提供了改进构建过程和 Webpack 整体性能的方法。至少在与内部模块图构建和处理无关的部分是这样。例如,JavaScript 和 TypeScript 的转译或代码精简。您可以使用esbuild-loader或swc-loader等更快的替代品来替换 Babel 转译器和 Terser 简化器,如ESBuild。
Webpack 的另一项有助于我们的应用程序实现更佳性能的功能是通过树形抖动减少最终捆绑包中的代码量。树状抖动是一种消除死代码的技术,它通过分析源代码中的导入和导出语句,确定哪些代码是应用程序实际使用的。Webpack 将从最终捆绑包中删除未使用的代码,从而使应用程序更小更高效。符合树状抖动条件的代码需要用 ECMAScript 模块(导入和导出语句)编写,并通过 package.json sideEffects: false 子句将自己标记为无副作用。
Metro 捆绑程序 GitHub 上的第一个问题 是关于 symlink 支持的。由于种种原因,Metro 无法以所需的 DX 引入该功能,因此该问题至今仍未解决。有一些方法可以缓解这一缺陷,但需要额外的配置。另一方面,Webpack 与其他任何捆绑程序一样,不存在这个问题。Re.Pack 在引擎盖下使用了 Webpack 捆绑程序,因此开箱即提供了 symlinks 功能,从开发者体验的角度来看,这对一些工作流程(如 monorepos)来说是非常宝贵的。
如果您使用的是 JavaScriptCore 引擎,Re.Pack 还能使用异步块将捆绑包分割成多个文件并按需加载,这可以改善初始加载时间。不过,如果与 Hermes一起使用,它的价值就没那么大了。Hermes 利用内存映射技术,只从 RAM 中直接动态读取捆绑包字节码的必要部分。不过,这其中也有曲折!Webpack 并不关心是从文件系统还是从远程加载动态块。因此,它允许从远程服务器或 CDN 直接动态加载应用程序捆绑包中从未出现过的代码。现在,这不仅能帮助你减少初始加载时间,还能减少宝贵的应用程序大小。
除此之外,Webpack 5 还引入了对 Module Federation 概念的支持。这是一种允许在独立应用程序之间代码拆分和共享拆分代码部分(或块)的功能。
它还能帮助分布式独立团队更快地发布大型应用程序。他们可以自由选择自己喜欢的 UI 框架并独立部署,同时还能共享相同的构建基础架构。Re.Pack 3 支持开箱即用的这一功能。
Metro 优于 Re.Pack 的地方
所有这些配置和灵活性都会影响构建过程。由于有自定义选项,构建速度比默认 Metro 捆绑程序稍长。此外,与 Metro 捆绑程序相比,快速刷新功能有限。热模块替换和 React Refresh 功能需要使用 Webpack 和 Re.Pack 重新加载整个应用程序,但 Metro 支持这些功能。
如果你不需要 Webpack 生态系统提供的大量定制功能,或者不打算拆分你的应用代码,那么你不妨保留默认的 Metro 捆绑程序。
react-native-esbuild
下一个可以帮助你优化 React Native 应用程序性能的捆绑程序是 react-native-esbuild,它具有速度快、树形晃动、兼容性和可配置性等特点。让我们来详细了解一下这个工具。
为什么值得为你的 React Native 项目考虑 react-native-esbuild
react-native-esbuild的主要优点之一是快速构建。它在引擎盖下使用了 ESBuild bundler,即使没有缓存,也能大大提高捆绑性能。与 Metro 捆绑程序相比,ESBuild 捆绑程序还提供了一些功能,如树形晃动,而且可配置性更强。
ESBuild 有自己的生态系统,包括插件、自定义转换器和环境变量。该加载器默认为 .ts、.tsx、.mts 和 .cts 文件启用,这意味着ESBuild 内置支持解析 TypeScript 语法并丢弃类型注解。但是,ESBuild 并不进行任何类型检查,因此您仍需要与 ESBuild 并行运行类型检查来检查类型。ESBuild 本身并不进行类型检查。
react-native-esbuild 的缺点
不幸的是,react-native-esbuild 有一些折衷方案,因此选择正确的捆绑程序也很重要。它不支持 Hermes,这可能是某些项目的关键点。它不支持快速刷新(Fast Refresh)或热模块替换(Hot Module Replacement),但该库支持实时重载。
rnx-kit
最后,我们要讨论的是微软的 rnx-kit。rnx-kit 是一个包含大量可扩展 React Native 开发工具的软件包。它还有一个自定义捆绑程序,可在 Metro 捆绑程序之上运行,并对其进行增强。
使用 rnx-kit 增强 Metro 的优点
如您所知,Metro 不支持 symlinks,而 rnx-kit 提供了完全处理 symlinks 的能力。与 Metro 相比,rnx-kit 的另一个优势是开箱即用的树形晃动功能。
Metro 支持 TypeScript 源文件,但只能将其转换为 JavaScript。rnx-kit 解决了这个问题。通过配置,可以启用类型检查。来自 TypeScript 的警告和错误会显示在控制台上。
此外,rnx-kit 还能提供开箱即用的重复依赖和循环依赖检测。这对减少捆绑包的大小非常有用,可提高性能并防止出现循环依赖问题。
在捆绑时,向用户发送更少的 JavaScript 并节省开发人员的时间
捆绑工具的选择取决于具体情况。不可能只为所有应用程序选择一种捆绑工具。如果您需要 Webpack 生态系统提供的自定义选项,或者计划拆分您的应用程序代码,那么我们建议您使用 Re.Pack,因为与其他捆绑工具相比,Re.Pack 具有广泛的自定义配置、海量加载器、由社区维护的插件以及 symlinks、别名等大量功能。
如果觉得 Webpack 生态系统开销太大,那么最好继续使用默认的 Metro 捆绑程序,或者尝试使用其他捆绑程序选项,如 react-native-esbuild 和 rnx-kit,它们也能提供一些好处,如缩短构建时间、在引擎盖下使用 esbuild、符号链接和开箱即用的类型脚本支持。不过,在使用新的捆绑系统时,一定要小心谨慎,注意权衡利弊。
如果您在性能、稳定性、用户体验或其他复杂问题上需要帮助,请 联系我们!作为 React Native 核心贡献者和活跃的开源贡献者,我们很乐意提供帮助。