使用 Angular 10 中的 ES 模块减小捆绑包大小





1.00/5 (1投票)
如果您担心应用程序的性能并且正在使用 CommonJS 模块,那么您还有另一个选择:ES 模块(EcmaScript 模块)。
2020 年 6 月,Angular 10 发布,带来了一系列新功能和修复。实现的新功能之一是,在构建使用 CommonJS 模块打包的依赖项的应用程序时,会显示一个警告。
发出此警告的原因是,在使用 CommonJS 模块进行生产构建时,可能会导致包大小增大。包大小的增加是由于 CommonJS 的设计方式,但我们稍后会详细介绍。如果您担心应用程序的性能并且正在使用 CommonJS 模块,那么您还有另一个选择:ES 模块(EcmaScript 模块)。
在本文中,我们将回顾模块格式系统如何影响打包大小、CommonJS 的问题、ES 模块如何解决这些问题,以及在使用 Wijmo 时如何实现 ES 模块。
模块和包大小
模块是开发人员通过模块范围更好地组织变量和函数的一种方式。模块范围可以被看作是全局范围;在模块范围内可用的变量和函数可以被同样可以访问模块范围的其他模块访问。
当某项内容可供其他模块访问时,它被称为导出。一旦创建了导出,其他模块就可以通过显式声明它们依赖于该变量、类或函数来导入它。
一旦您的应用程序可以在模块之间导入和导出变量和函数,您就可以通过将其分解成较小的块并在需要时导入其功能来更轻松地组织您的应用程序。
由于变量和函数现在分散在多个文件中,因此在进行生产构建时,您的应用程序需要将所有内容打包在一起。您的模块系统如何处理导入和导出功能,以及模块系统决定需要导入什么,都会影响您的包的大小。
由于模块如此有用,因此已经进行了多次尝试将模块/模块功能引入 JavaScript。最流行的两种模块系统是 CommonJS 和 ES 模块。
CommonJS 和 ES 模块
CommonJS 是一个为 JavaScript 创建的模块格式系统,于 2009 年发布。自那时以来,它已成为组织和管理 JavaScript 代码的标准。最初为服务器端应用程序设计,该标准极大地影响了 NodeJS 组织其模块管理的方式。
使用 CommonJS,您可以定义模块,从中导出功能,并使用 require
函数在其他模块中导入它们。
例如,如果您有一个用于验证用户输入的函数,该函数可在其模块中导出,则可以使用 require
函数让其他模块访问它。
// verify.js
exports.verifyInput = (userInput) => /* code implementation */
// index.js
const { verifyInput } = require(‘./verify.js’);
…
const validData = verifyInput(userInput);
由于 verifyInput
函数被导出,我们现在可以在 index.js 文件中使用 require
方法导入该功能并加以利用。
由于 CommonJS 最初是为服务器端应用程序创建的,因此在客户端应用程序上运行带来了性能成本,而在服务器端应用程序上这些成本可以忽略不计。然而,由于 CommonJS 创建时浏览器中缺乏标准化的模块系统,因此它也成为 JavaScript 客户端库流行的模块格式系统。
由于客户端应用程序存在这些性能和优化问题,因此 ES 模块的创建考虑到了浏览器。导入和导出功能与 CommonJS 非常相似;您将使用 import 语句,而不是使用 require
来导入变量和函数。
// verify.js
exports.verifyInput => /* code implementation */
// index.js
import verifyInput from ‘./verify.js’;
…
const validData = verifyInput(userInput);
ES 模块和 CommonJS 之间的主要区别在于模块的加载方式。CommonJS 更具动态性,而 ES 模块更具静态性。
举个例子,当从另一个模块导入功能时,CommonJS 允许您将变量传递到路径中,而 ES 模块则要求它是一个字符串字面量。
// CommonJS
const { verifyinput } = require(‘./${path}/verify.js’);
// ES Modules
import verifyInput from (‘./${path}/verify.js’); // Will not work
import verifyInput from (‘./login/verify.js); // Will work
CommonJS 可以采取这种动态方法,因为它加载依赖项的方式。当 CommonJS 需要加载模块时,它是在运行时完成的。模块被同时加载、实例化和评估。这就是为什么您可以通过将变量传递到文件路径(尽管这只是一个简单的例子)的原因。由于这是在运行时完成的,因此应用程序进行“摇树优化”(tree-shaking)会更加困难。
摇树优化(Tree-shaking)是指您的应用程序可以从文件中删除任何未使用的功能,以使您的应用程序更小。这些包括删除未使用的函数、注释和多余的空格。
由于 CommonJS 在运行时全部加载、实例化和评估,因此摇树优化更难发生,并且在发生时效率更低。之所以能够进行摇树优化,是因为 webpack 能够静态地(在构建时)理解我们正在导入什么以及导出了什么。
ES 模块没有这个问题。因为 ES 模块比 CommonJS 更具静态性,所以它们更易于静态分析。加载、实例化和评估被分解为三个不同的阶段,可以分开进行,而不是像 CommonJS 那样一起进行。这使得摇树优化更加高效。
将 ES 模块与 Wijmo 结合使用
随着 Wijmo 2020v2 的发布,Wijmo 支持使用 ES 模块。ES 模块的使用默认启用,这意味着您无需采取任何措施即可使用 ES 模块。
根据我们的测试,包含 Wijmo 组件的包大小预计会减小约 30%。
您可以在下方查看使用 ES 模块与 CommonJS 配合使用 Wijmo 时包大小减小的细分情况。
请注意:如果您希望继续将 CommonJS 模块与 Wijmo 一起使用,可以通过运行以下命令来实现:
npm run wijmo-esm -- -disable
如果您在使用 wijmo-esm 时遇到任何问题,也可以运行以下命令获取更多信息。
npm run wijmo-esm -- -help
要以生产模式构建您的应用程序,您需要在 package.json 文件的“scripts”部分添加以下命令:
"prod": "ng build --prod",
然后,您可以通过运行 npm run –prod
来构建您的应用程序,并在创建的 dist 文件夹中看到打包好的文件。