关于angular:Angular-Package-Format-APF-v120-介绍

33次阅读

共计 3874 个字符,预计需要花费 10 分钟才能阅读完成。

官网

本文档形容了 npm 上以后可用的 Angular 框架包的构造和格局。这种格局实用于散发 Angular 组件的包(如 Angular Material)以及在 @angular 命名空间下公布的外围框架包,如 @angular/core 和 @angular/forms。

此处形容的格局应用独特的文件布局和元数据配置,使包可能在应用 Angular 的大多数常见场景下无缝工作,并使其与 Angular 团队和社区自身提供的工具兼容。出于这个起因,也强烈激励第三方库开发人员遵循雷同的构造。

格局的版本控制与 Angular 自身的版本控制统一,咱们心愿格局以向前兼容 (forward-compatible) 的形式倒退,以反对 Angular 组件和工具生态系统的需要。

Package format 的目标

在当今的 JavaScript 环境中,开发人员将以多种不同的形式应用包。例如,有些可能应用 SystemJS,有些可能应用 Webpack。尽管如此,其他人可能会在 Node 或浏览器中应用包作为 UMD 包或通过全局变量拜访。

Angular 散发包反对所有罕用的开发工具和工作流,并强调优化,从而放大应用程序无效负载大小或放慢开发迭代周期(构建工夫)。

Library File layout

库个别应该应用雷同的布局,但库中存在与 Angular 框架不同的个性。

通常,库是在组件或性能级别拆分的。咱们以 Angular 的 Material 我的项目为例。

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+ES2015、CJS+ES5、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 等工具在应用程序级进行操作。

更多 Jerry 的原创文章,尽在:” 汪子熙 ”:

正文完
 0