使用 ng-packagr 打包 Angular

yzf01發表於2021-09-09

寫在前面

為了讓 Angular 類庫應用範圍更自由,Angular 提出一套打包格式建議名曰:,包括 FESM2015、FESM5、UMD、ESM2015、ESM5、ES2015 格式,不同格式可以在不同的環境(Angular Cli、Webpack、SystemJS等)中使用。

傳統方式需要對這些格式逐一打包,一個打包指令碼寫法。這種寫法只能針對不同專案的配置,而且除非你瞭解這些格式的本質否則很難維護;後來社群根據 APF 規範實現了類庫 ,透過簡單的配置可以將你的類庫打包成 APF 規範格式。

至 V6 以後 Angular Cli 也基於 ng-packagr 實現了另一個 @angular-devkit/build-ng-packagr 應用構建器。

如何使用

既然 ng-packagr 被 Angular Cli 內建,這讓我們進一步簡化了生產一個 APF 規範格式的類庫的成本。在 Angualr Cli 裡使用 ng g library 來建立一個類庫模板,例如在一個新的 Angular 應用裡執行:

ng g library 

而打包,則:

ng build 

最終,將生成的 dist/ 目錄下檔案上傳相應包管理伺服器(例如:npm)提供給其他 人使用。

配置說明

由 Angular Cli 生成的類庫模板大部分內容同 Angular 應用一樣,只是多了一個 ng-package.json 的配置檔案(對於生產環境是 ng-package.prod.json),它是專門針對 ng-packagr 的一個配置檔案,如同 angular.json 一般也是基於 JSON Schema 格式,因此可以透過訪問 瞭解所有細節,以下描述一些重點項。

whitelistedNonPeerDependencies

ng-packagr 預設會根據 package.json 的 peerDependencies 節點清單來決定類庫所需要第三方依賴包,這些依賴包是不會被打包至類庫。

然而,所依賴包不存在 peerDependencies 節點裡時(當然建議需要依賴的項應該在裡面),就需要該屬性的配置。

lib/entryFile

指定入口檔案。

lib/umdModuleIds

UMD 格式採用 rollup 打包,當類庫需要引用一些無法猜出正確 UMD 識別符號時,就需要你手動對映這些類庫的標識。

"umdModuleIds": {    "lodash": "_"}

angular.json

Angular Cli 配置檔案 angular.json 內會增加一個以 命名的構建配置,絕大多數配置性同普通 Angular 應用如出一轍,唯一不同的是 builder 節點為:

"builder": "@angular-devkit/build-ng-packagr:build"

次級入口

有時候一個類庫可能會包含著多個二次入口,就像 @angular/core 類庫包含著一個 @angular/core/testing 模組,它只是運用於測試,因此並不希望在專案中引入 @angular/core 時也包含測試程式碼,但同時二者又是同一個功能性時,這種次級匯入顯得非常重要。

另一種像 ngx-bootstrap、@angular/cdk/ally 等都提供次級模組的匯入,可以更好的最佳化體積。

不論出於何種目的,都可以透過 Angular Cli 簡單的檔案組織進一步打包出主、次級分明的類庫。

ng g library 生成的結構大概如下:


├── src|   ├── public_api.ts
|   └── lib/*.ts
├── ng-package.json
├── ng-package.prod.json
├── package.json
├── tsconfig.lib.json
└── tsconfig.spec.json

當根目錄下包含 README.mdLICENSE 時會自動被複制到 dist 目錄中,Npm 規定必須包含 README.md 檔案,否則訪問已釋出類庫頁時會有未找到描述檔案錯誤提示。

若想建立一個 /testing 的次級入口,只需要在 根目錄下建立一個 testing 目錄:


├── src|   ├── public_api.ts
|   └── lib/*.ts
├── ng-package.json
├── ng-package.prod.json
├── package.json
├── tsconfig.lib.json
├── tsconfig.spec.json
└── testing
    ├── src    |   ├── public_api.ts
    |   └── *.ts
    └── package.json

核心是需要提供一個 package.json 檔案,而且內容簡單到姥姥家。

{    "ngPackage": {}
}

最後,依然使用 ng build ,會產生一個次級匯入模組。

小結

至此,基本上利用 Angular Cli 可以快速的構建一個可釋出於 Npm Angular 類庫,更復雜的可以構建像 ngx-bootstrap、@angular/cdk/* 類庫。

自定義構建

Angular Cli 雖然提供非常便利的環境,但是對於一些複雜環境像 Delon 類庫(基建系列類庫)包含著多個類庫、類庫又包含多個次級匯入時,Angular Cli 會顯得有點囉嗦,特別是對每個類庫的 angular.json 配置。其實 @angular-devkit/build-ng-packagr 非常簡單,如果將取進一步簡化,整個實現差不多相當於:

const path = require('path');const ngPackage = require('ng-packagr');const target = path.resolve(__dirname, './projects/');

ngPackage
  .ngPackagr()
  .forProject(path.resolve(target, `ng-package.prod.json`))
  .withTsConfig(path.resolve(target, 'tsconfig.lib.json'))
  .build()
  .then(() => {      // 構建完成後乾點事
  });

將上面的程式碼放到 ./build.js,執行:

node scripts/build.js

其結果完成是等價。

build() 返回的是一個 Promise 物件,意味著可以確保構建開始前和結束後做一點額外的事。

總結

ng-packagr 極大簡化 Angular 類庫被打包出一個 APF 規範建議,雖然它以 ng- 開頭,但本質上並不一定非要在 Angular 中運用,也可以使用在 React、VUE。



作者:cipchk
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2334/viewspace-2814758/,如需轉載,請註明出處,否則將追究法律責任。

相關文章