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 等工具在應用程序級進行操做。

相關文章
相關標籤/搜索