新聞中心
Angular 包格式
本文檔描述了 Angular 包格式 (APF)。APF 是針對 npm 包結構和格式的 Angular 專用規(guī)范,所有第一方 Angular 包(?@angular/core? 、 ?@angular/material? 等)和大多數第三方 Angular 庫都使用了該規(guī)范。

成都創(chuàng)新互聯(lián)-專業(yè)網站定制、快速模板網站建設、高性價比香河網站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式香河網站制作公司更省心,省錢,快速模板網站建設找我們,業(yè)務覆蓋香河地區(qū)。費用合理售后完善,10余年實體公司更值得信賴。
APF 能讓包在使用 Angular 的大多數常見場景下無縫工作。使用 APF 的包與 Angular 團隊提供的工具以及更廣泛的 JavaScript 生態(tài)系統(tǒng)兼容。建議第三方庫開發(fā)者也都遵循這種格式。
APF 與 Angular 的其余部分一起進行版本控制,每個主要版本都改進了包格式。你可以在此 google doc 中找到 v13 之前版本的規(guī)范。
為什么要指定包格式?
在當今的 JavaScript 環(huán)境中,開發(fā)人員將使用多種不同的工具鏈(Webpack、rollup、esbuild 等)以多種不同的方式使用包。這些工具可能理解并需要不同的輸入 —— 一些工具能處理最新的 ES 語言版本,而其他工具也許要直接使用較舊的 ES 版本。
這種 Angular 分發(fā)格式支持所有常用的開發(fā)工具和工作流,并著重于優(yōu)化,從而縮小應用程序有效負載大小或縮短開發(fā)迭代周期(構建時間)。
開發(fā)人員可以依靠 Angular CLI 和 ng-packagr(Angular CLI 使用的構建工具)來生成 APF 格式的包。
文件布局
以下示例顯示了 ?@angular/core? 包文件布局的簡化版本,并附有對包中每個文件的解釋。
此表描述了 ?node_modules/@angular/core? 下的文件布局,注釋為描述文件和目錄的用途:
|
文件 |
用途 |
|---|---|
README.md | |
package.json | |
index.d.ts | |
esm2020/testing/ | |
fesm2015/─ core.mjs─ core.mjs.map─ testing.mjs─ testing.mjs.map | |
fesm2020/─ core.mjs─ core.mjs.map─ testing.mjs─ testing.mjs.map | |
testing/ | |
testing/index.d.ts | |
package.json
主 ?package.json? 包含重要的包元數據,包括以下內容:
- 它把此包聲明為 EcmaScript 模塊 (ESM) 格式
- 它包含一個 ?
"exports"? 字段,用于定義所有入口點的可用源碼格式 - 它包含定義主入口點 ?
@angular/core? 的可用源碼格式的一些鍵,供不理解 ?"exports"? 的工具使用。這些鍵已棄用,隨著對 ?"exports"? 的支持在整個生態(tài)系統(tǒng)中逐步退出,這些鍵將被刪除。 - 它聲明此包是否包含副作用
ESM 聲明
頂級 ?package.json? 包含此鍵:
{
"type": "module"
}這會通知解析器,此包中的代碼正在使用 EcmaScript 模塊而不是 CommonJS 模塊。
"exports"
?"exports"? 字段具有以下結構:
"exports": {
"./schematics/*": {
"default": "./schematics/*.js"
},
"./package.json": {
"default": "./package.json"
},
".": {
"types": "./core.d.ts",
"esm2020": "./esm2020/core.mjs",
"es2020": "./fesm2020/core.mjs",
"es2015": "./fesm2015/core.mjs",
"node": "./fesm2015/core.mjs",
"default": "./fesm2020/core.mjs"
},
"./testing": {
"types": "./testing/testing.d.ts",
"esm2020": "./esm2020/testing/testing.mjs",
"es2020": "./fesm2020/testing.mjs",
"es2015": "./fesm2015/testing.mjs",
"node": "./fesm2015/testing.mjs",
"default": "./fesm2020/testing.mjs"
}
}主要看 "." 和 "./testing" 這兩個鍵,它們分別定義了 @angular/core 主要入口點和 @angular/core/testing 次要入口點的可用代碼格式。對于每個入口點,可用的格式為:
|
格式 |
詳情 |
|---|---|
es2020 | |
es2015 | |
esm2020 | |
認識這些鍵的工具可以優(yōu)先從 ?"exports"? 中選擇所需的代碼格式。其余 2 個鍵控制工具的默認行為:
- ?
"node"? 在 Node.js 中加載包時選擇扁平化的 ES2015 代碼。
使用這種格式是由于 ?zone.js? 的要求,因為它不支持原生的 ?async ?/ ?await ?ES2017 語法。因此,指示 Node 使用 ES2015 代碼,其中 ?async ?/ ?await ?結構已降級為 Promises。
- ?
"default"? 為所有其他消費者選擇扁平化的 ES2020 代碼。
庫可能希望公開其他靜態(tài)文件,這些文件沒有被基于 JavaScript 的入口點(比如 Sass mixins 或預編譯的 CSS)的導出所捕獲。
舊版解析鍵
除了 ?"exports"? 之外,頂級 ?package.json? 還為不支持 ?"exports"? 的解析器定義了舊模塊解析鍵。對于 ?@angular/core?,這些是:
{
"fesm2020": "./fesm2020/core.mjs",
"fesm2015": "./fesm2015/core.mjs",
"esm2020": "./esm2020/core.mjs",
"typings": "./core.d.ts",
"module": "./fesm2015/core.mjs",
"es2020": "./fesm2020/core.mjs",
}如上,模塊解析器可以用這些鍵來加載特定的代碼格式。
注意:
與 ?
"default"? 不同,?
"module"? 是為 Node 以及任何未配置為使用特定鍵的工具選擇的格式。它基本和 ?
"node"? 一樣,但由于 ZoneJS 的限制,選擇了 ES2015 代碼。
副作用
?package.json? 的最后一個功能是聲明此包是否有副作用。
{
"sideEffects": false
}大多數 Angular 包不應該依賴于頂級副作用,因此應該包含這個聲明。
入口點和代碼拆分
APF 中的包,包含一個主要入口點和零到多個次要入口點(比如 ?@angular/common/http?)。入口點有多種功能。
- 它們定義了用戶要從中導入代碼的模塊說明符(比如,?
@angular/core? 和 ?@angular/core/testing?)。 - 它們定義了可以惰性加載代碼的粒度。
用戶通常將這些入口點視為具有不同用途或功能的不同符號組。
特定入口點可能僅用于特殊目的,比如測試。此類 API 可以與主入口點分離,以減少它們被意外或錯誤使用的機會。
許多現代構建工具只能在 ES 模塊級別進行“代碼拆分”(又名惰性加載)。由于 APF 主要為每個入口點使用一個“扁平” ES 模塊,這意味著大多數構建工具無法將單個入口點中的代碼拆分為多個輸出塊。
APF 包的一般規(guī)則是為盡可能小的邏輯相關代碼集使用入口點。比如,Angular Material 包將每個邏輯組件或一組組件作為單獨的入口點發(fā)布 - 一個用于按鈕,一個用于選項卡等。如果需要,這允許單獨惰性加載每個 Material 組件。
并非所有庫都需要這樣的粒度。大多數具有單一邏輯目的的庫應該作為單一入口點發(fā)布。比如 ?@angular/core? 為運行時使用單個入口點,因為 Angular 運行時通常用作單個實體。
次要入口點的解析
可以通過包的 ?package.json? 的 ?"exports"? 字段解析輔助入口點。
自述文件
markdown 格式的自述文件,用于在 npm 和 github 上顯示包的描述。
?@angular/core? 包的示例自述內容:
Angular
=======
The sources for this package are in the main [Angular](https://github.com/angular/angular) repo.Please file issues and pull requests against that repo.
License: MIT部分編譯
APF 格式的庫必須以“部分編譯”模式發(fā)布。這是 ?ngc ?的一種編譯模式,它生成不依賴于特定 Angular 運行時版本的已編譯 Angular 代碼,與用于應用程序的完整編譯形成對比,其中 Angular 編譯器和運行時版本必須完全匹配。
要部分編譯 Angular 代碼,請在 ?tsconfig.json? 中的 ?"angularCompilerOptions"? 中使用 ?"compilationMode"? 標志:
{
…
"angularCompilerOptions": {
"compilationMode": "partial",
}
}然后,在應用程序構建過程中,Angular CLI 將部分編譯的庫代碼轉換為完全編譯的代碼。
優(yōu)化
ES 模塊的扁平化
APF 指定代碼要以“扁平化”的 ES 模塊格式發(fā)布。這顯著減少了 Angular 應用程序的構建時間以及最終應用程序包的下載和解析時間。請查看 Nolan Lawson 發(fā)表的優(yōu)秀文章“小模塊的成本”。
Angular 編譯器支持生成索引 ES 模塊文件,然后可以讓這些文件借助 Rollup 等工具生成扁平化模塊,從而生成我們稱為扁平化 ES 模塊或 FESM 的文件格式。
FESM 是一種文件格式,它會將所有可從入口點訪問的 ES 模塊扁平化為單個 ES 模塊。它是通過跟蹤包中的所有導入并將該代碼復制到單個文件中而生成的,同時保留所有公共 ES 導出并刪除所有私有導入。
縮寫名稱“FESM”(發(fā)音為“phesom”)后面可以有一個數字,比如“FESM5”或“FESM2015”。數字是指模塊內 JavaScript 的語言級別。所以 FESM5 文件將是 ESM+ES5(導入/導出語句和 ES5 源代碼)。
要生成扁平化的 ES 模塊索引文件,請在 tsconfig.json 文件中使用以下配置選項:
{
"compilerOptions": {
…
"module": "esnext",
"target": "es2020",
…
},
"angularCompilerOptions": {
…
"flatModuleOutFile": "my-ui-lib.js",
"flatModuleId": "my-ui-lib"
}
}一旦 ngc 生成了索引文件(比如 ?my-ui-lib.js?),打包器和優(yōu)化器(如 Rollup)就可用于生成扁平化的 ESM 文件。
注意 package.json 中的默認值
從 webpack v4 開始,對于 webpack 用戶來說,ES 模塊優(yōu)化的扁平化應該不是必需的,其實理論上我們應該能夠在不扁平化 webpack 中的模塊的情況下獲得更好的代碼拆分。在實踐中,當使用非扁平化模塊作為 webpack v4 的輸入時,我們仍然會看到大小增加了。這就是為什么 package.json 中的 ?"module"? 和 ?"es2020"? 條目仍然指向 fesm 文件的原因。我們正在調查此問題,并希望在解決大小回歸問題后將 package.json 中的 ?"module"? 和 ?"es2020"? 入口點切換到未扁平化的文件。APF 目前包含未扁平化的 ESM2020 代碼,目的是驗證此類未來的更改。
“副作用”標志
默認情況下,EcmaScript 模塊是有副作用的:從模塊導入可確保該模塊頂層的任何代碼都將執(zhí)行。這通常是不可取的,因為典型模塊中的大多數副作用代碼并不是真正的副作用,而是僅影響特定符號。如果沒有導入和使用這些符號,通常需要在稱為 tree-shaking 的優(yōu)化過程中將它們刪除,而副作用代碼可以防止這種情況發(fā)生。
諸如 Webpack 之類的構建工具支持一個標志,該標志允許包聲明它們并不依賴于其模塊頂層的副作用代碼,從而使工具可以更自由地對包中的代碼進行搖樹優(yōu)化。這些優(yōu)化的最終結果應該是較小的包大小和代碼拆分后包塊中更好的代碼分布。如果此優(yōu)化包含非本地副作用,則此優(yōu)化可能會破壞你的代碼 - 然而,這在 Angular 應用程序中并不常見,并且通常是糟糕設計的標志。我們的建議是讓所有包通過將 sideEffects 屬性設置為 false 來聲明無副作用狀態(tài),并且讓開發(fā)人員遵循 Angular 風格指南,這自然會導致代碼沒有非本地副作用。
更多信息:關于副作用的 webpack 文檔
ES2020 語言級別
ES2020 語言級別現在是 Angular CLI 和其他工具使用的默認語言級別。Angular CLI 會將捆綁包降級到所有目標瀏覽器在應用程序構建時都支持的語言級別。
d.ts 捆綁/類型定義的扁平化
從 APF v8 開始,我們現在更喜歡運行 API Extractor 來打包 TypeScript 定義,以便整個 API 都出現在單個文件中。
在之前的 APF 版本中,每個入口點都會在 .d.ts 入口點旁邊有一個 ?src ?目錄,該目錄包含與原始源代碼結構匹配的單個 d.ts 文件。雖然這種分發(fā)格式仍然被允許和支持,但非常不鼓勵它,因為它會弄暈 IDE 之類的工具,然后提供錯誤的自動完成,并允許用戶依賴深度導入的路徑,這些路徑通常不被認為是庫或包的公共 API。
庫
從 APF v10 開始,我們建議添加 tslib 作為主要入口點的直接依賴項。這是因為 tslib 版本與用來編譯庫的 TypeScript 版本相關聯(lián)。
術語定義
本文檔中特意使用了以下術語。在本節(jié)中,我們定義所有這些以便更清晰。
包
發(fā)布到 NPM 并一起安裝的最小文件集,比如 ?@angular/core?。該包中包含一個名為 package.json 的清單、編譯后的源代碼、TypeScript 定義文件、源碼映射、元數據等。該包是通過 ?npm install @angular/core? 安裝的。
符號
包含在模塊中的類、函數、常量或變量,可選擇通過模塊導出,以便對外界可見。
模塊
ECMAScript 模塊的縮寫。包含導入和導出符號的語句的文件。這與 ECMAScript 規(guī)范中模塊的定義相同。
ESM
ECMAScript 模塊的縮寫(見上文)。
FESM
Flattened ES Modules 的縮寫,由一種文件格式組成,該文件格式是通過將所有可從入口點訪問的 ES 模塊扁平化為單個 ES 模塊而創(chuàng)建的。
模塊標識
導入語句中使用的模塊的標識符(比如 ?@angular/core?)。此 ID 通常直接映射到文件系統(tǒng)上的路徑,但由于有各種模塊解析策略,情況也并非總是如此。
模塊說明符
模塊標識符(見上文)。
模塊解析策略
用于將模塊 ID 轉換為文件系統(tǒng)路徑的算法。Node.js 就有一個良好定義且廣泛使用的,TypeScript 支持多種模塊解析策略,Closure Compiler 還有另一種策略。
模塊格式
模塊語法規(guī)范,至少涵蓋用于從文件導入和導出的語法。常見的模塊格式是 CommonJS(CJS,通常用于 Node.js 應用程序)或 ECMAScript 模塊(ESM)。模塊格式僅表示單個模塊的封裝,而不表示用于構成模塊內容的 JavaScript 語言特性。正因為如此,Angular 團隊經常使用語言級別說明符作為模塊格式的后綴,比如 ESM+ES2015 指定模塊為 ESM 格式并包含降級到 ES2015 的代碼。
捆綁包
單個 JS 文件形式的工件,由構建工具(比如 Webpack或Rollup)生成,其中包含源自一個或多個模塊的符號。捆綁包是一種瀏覽器專用的解決方案,可減少瀏覽器開始下載數百甚至數萬個文件時可能造成的網絡壓力。Node.js 通常不使用捆綁包。常見的捆綁包格式是 UMD 和 System.register。
語言級別
代碼的語言(ES2015 或 ES2020)。獨立于模塊格式。
入口點
旨在由用戶導入的模塊。它由唯一的模塊 ID 引用,并導出該模塊 ID 引用的公共 API。一個例子是 ?@angular/core? 或 ?@angular/core/testing?。?@angular/core? 包中存在兩個入口點,但它們導出不同的符號。一個包可以有許多入口點。
深度導入
從不是入口點的模塊中檢索符號的過程。這些模塊 ID 通常被認為是私有 API,它們可以在項目的生命周期內或在創(chuàng)建給定包的捆綁包時更改。
頂級導入
來自入口點的導入??捎玫捻敿墝攵x了公共 API,并在“@angular/name”模塊中公開,比如 ?@angular/core? 或 ?@angular/common?。
搖樹優(yōu)化
識別和刪除應用程序中未使用的代碼的過程 - 也稱為死代碼消除。這是使用 Rollup 、 Closure Compiler 或 Terser 等工具在應用程序級別執(zhí)行的全局優(yōu)化。
AOT 編譯器
Angular 的預先編譯器。
扁平類型定義
從 API Extractor 生成的捆綁 TypeScript 定義。
網站標題:創(chuàng)新互聯(lián)Angular教程:Angular 包格式
路徑分享:http://www.dlmjj.cn/article/cddohjs.html


咨詢
建站咨詢
