Angular Package Format (APF) v12.0 介绍

 

本文档描述了 npm 上当前可用的 Angular 框架包的结构和格式。 这种格式适用于分发 Angular 组件的包(如 Angular Material)以及在@angular 命名空间下发布的核心框架包,如@angular/core 和@angular/forms。html

此处描述的格式使用独特的文件布局和元数据配置,使包可以在使用 Angular 的大多数常见场景下无缝工做,并使其与 Angular 团队和社区自己提供的工具兼容。 出于这个缘由,也强烈鼓励第三方库开发人员遵循相同的结构。npm

格式的版本控制与 Angular 自己的版本控制一致,咱们但愿格式以向前兼容(forward-compatible)的方式发展,以支持 Angular 组件和工具生态系统的需求。json

Package format 的目的

在当今的 JavaScript 环境中,开发人员将以多种不一样的方式使用包。 例如,有些可能使用 SystemJS,有些可能使用 Webpack。 尽管如此,其余人可能会在 Node 或浏览器中使用包做为 UMD 包或经过全局变量访问。浏览器

Angular 分发包支持全部经常使用的开发工具和工做流,并强调优化,从而缩小应用程序有效负载大小或加快开发迭代周期(构建时间)。网络

Library File layout

库通常应该使用相同的布局,但库中存在与 Angular 框架不一样的特性。框架

一般,库是在组件或功能级别拆分的。咱们以 Angular 的 Material 项目为例。ide

Angular Material 发布了组件集,例如 Button(单个组件)、Tabs(一组协同工做的组件)等。共同点是将这些功能区域绑定在一块儿的 NgModule。 Button 有一个 NgModule,Tabs 有另外一个,依此类推。函数

Angular Package Format 的通常规则是为最小的逻辑链接代码集生成 FESM 文件。例如,Angular 包有一个用于@angular/core 的 FESM。当开发人员使用来自@angular/core 的 Component 符号时,他们极可能也会直接或间接使用诸如 Injectable、Directive、NgModule 等符号。所以,全部这些部分都应该捆绑在一块儿造成一个 FESM。对于大多数库状况,应该将单个逻辑组组合到一个 NgModule 中,而且全部这些文件应该捆绑在一块儿做为包中的单个 FESM 文件,表明 npm 包中的单个入口点。工具

如下是 Angular Material 项目在这种格式下的外观示例:布局

再看 Spartacus core build 出来的输出:

Primary Entry point

包的主要入口点是模块 id 与包名称匹配的模块(例如,对于“@angular/core”包,从主要入口点导入的内容以下: import {Component, ...} from '@ 角度/核心')。

Secondary Entry point

除了主要入口点,包能够包含零个或多个次要入口点(例如@angular/common/http)。 这些包含咱们不想与主入口点中的符号组合在一块儿的符号,缘由有两个:

(1)用户一般认为它们与主要符号组不一样,而且若是它们与主要符号组相关,那么他们就已经在那里了。

(2)次要组中的符号一般仅用于特定场景(例如,在编写和运行测试时)。 可能不会在主入口点中包含这些符号,所以咱们减小了它们被意外错误使用的机会(例如,在@angular/core/testing 中使用的生产代码中使用测试模拟)。

辅助入口点导入的模块 ID 将模块加载器定向到辅助入口点名称的目录。 例如,“@angular/core/testing”解析为一个同名的目录,“@angular/core/testing”。 该目录包含一个 package.json 文件,该文件将加载器定向到它正在寻找的正确位置。 这容许咱们在单个包中建立多个入口点。

Compilation and transpilation

为了生成全部必需的构建工件,咱们强烈建议您使用 Angular 编译器 (ngc) 使用 tsconfig.json 中的如下设置编译您的代码:

{
  "compilerOptions": {
    ...
    "declaration": true,
    "module": "es2015",
    "target": "es2015"
  },
  "angularCompilerOptions": {
    "strictMetadataEmit": true,
    "skipTemplateCodegen": true,
    "flatModuleOutFile": "my-ui-lib.js",
    "flatModuleId": "my-ui-lib",
  }
}

优化相关

Flattening of ES Modules

咱们强烈建议您在将构建工件发布到 npm 以前,经过扁平化 ES 模块来优化构建工件。这显着减小了 Angular 应用程序的构建时间以及最终应用程序包的下载和解析时间。

Angular 编译器支持生成索引 ES 模块文件,而后可使用这些文件使用 Rollup 等工具生成扁平化模块,从而生成咱们称为扁平化 ES 模块或 FESM 的文件格式。

FESM 是一种文件格式,经过将全部可从入口点访问的 ES 模块扁平化为单个 ES 模块。它是经过跟踪包中的全部导入并将该代码复制到单个文件中而造成的,同时保留全部公共 ES 导出并删除全部私有导入。

缩写名称“FESM”(发音为“phesom”)后面能够有一个数字,例如“FESM5”或“FESM2015”。数字是指模块内 JavaScript 的语言级别。因此 FESM5 文件将是 ESM+ES5(导入/导出语句和 ES5 源代码)。

要生成扁平化的 ES 模块索引文件,请在 tsconfig.json 文件中使用如下配置选项:

{
  "compilerOptions": {
    ...
    "module": "es2015",
    "target": "es2015",
    ...
  },
  "angularCompilerOptions": {
    ...
    "flatModuleOutFile": "my-ui-lib.js",
    "flatModuleId": "my-ui-lib"
  }
}

一旦索引文件(例如 my-ui-lib.js)由 ngc 生成,捆绑器和优化器(如 Rollup)可用于生成扁平化的 ESM 文件。

Inlining of templates and stylesheets

组件库一般使用存储在单独文件中的样式表和 html 模板来实现。 虽然不是必需的,但咱们建议组件做者经过将 styleUrls 和 templateUrl 分别替换为样式和模板元数据属性,将模板和样式表内联到他们的 FESM 文件以及 *.metadata.json 文件中。 这简化了应用程序开发人员对组件的使用。

从 APF v10 开始,咱们建议添加 tslib 做为主要入口点的直接依赖项,这是由于 tslib 版本与用于编译库的 TypeScript 版本相关联。

一些术语
  • package: 发布到 NPM 并安装在一块儿的最小文件集,例如 @angular/core。 该包包含一个名为 package.json 的清单、编译后的源代码、TypeScript files、源映射、元数据等。该包经过 npm install @angular/core 安装。

  • Symbols:包含在模块中的类、函数、常量或变量,并可选择经过模块导出对外部世界可见。

  • module ID: 导入语句中使用的模块的标识符,例如 “@spartacus/core”。 ID 一般直接映射到文件系统上的路径,但因为各类模块解析策略,状况并不是老是如此。

  • module format:模块语法规范,至少涵盖用于从文件导入和导出的语法。 常见的模块格式是 CommonJS(CJS,一般用于 Node.js 应用程序)或 ECMAScript 模块(ESM)。 模块格式仅表示单个模块的封装,而不表示用于构成模块内容的 JavaScript 语言特性。 所以,Angular 团队常用语言级别说明符做为模块格式的后缀,例如 ESM+ES5 指定模块采用 ESM 格式并包含下级到 ES5 的代码。 其余经常使用组合:ESM+ES201五、CJS+ES五、CJS+ES2015。

  • bundle: 由构建工具生成的单个 JS 文件形式的工件,例如 WebPack 或 Rollup,包含源自一个或多个模块的符号。 捆绑包是一种特定于浏览器的解决方法,可减小浏览器开始下载数百甚至数万个文件时可能形成的网络压力。 Node.js 一般不使用包。 常见的捆绑格式是 UMD 和 System.register。

  • language level: 代码的语言(ES5 或 ES2015)。 独立于模块格式。

  • entry point: 打算由用户导入的模块。 它由惟一的模块 ID 引用,并导出该模块 ID 引用的公共 API。 一个例子是@angular/core 或@angular/core/testing。 @angular/core 包中存在两个入口点,但它们导出不一样的符号。 一个包能够有许多入口点。

  • deep import: 从不是入口点的模块中检索符号的过程。 这些模块 ID 一般被认为是私有 API,它们能够在项目的生命周期内或在建立给定包的包时更改。

  • top level import: 来自入口点的导入。 可用的顶级导入定义了公共 API,并在“@angular/name”模块中公开,例如 @angular/core 或 @angular/common。

  • tree shaking: 识别和删除应用程序未使用的代码的过程 - 也称为死代码消除。 这是使用 Rollup、Closure Compiler 或 Uglify 等工具在应用程序级进行操做。

相关文章
相关标签/搜索