为什么我们需要给 Angular library 创建多重入口 multiple entry point
原文:Creating Secondary Entry Points for your Angular Library
自從 Angular 庫功能(從 Angular 7 開始)發布以來,現在開發 Angular 庫比以往任何時候都容易。 Angular 庫本身配備了一個名為 ng-packagr 的社區驅動包,它幾乎是核心。 在本文中,我們將看看如何利用 ng-packagr 輔助入口點進一步拆分我們的 Angular 庫!
Why do we need secondary entry points?
我們希望擁有輔助入口點的原因之一是使我們能夠拆分我們的依賴項。 讓我們看一個例子,其中一個模塊有 peerDependencies,而另一個沒有。
假設我們有如下的 library 文件夾結構:
library 名稱:my-awesome-lib
兩個 module,awesome-plain 和 awesome-time
查看 awesome-plain Component 的實現:
import { Component } from '@angular/core'; @Component({selector: 'awesome-plain',template: `<div>Hey I'm just a plain text with no dependencies!</div>` }) export class AwesomePlainComponent {}以及 awesome-time Component 的實現:
import { Component } from '@angular/core'; import * as moment_ from 'moment'; const moment = moment_; @Component({selector: 'awesome-time',template: `<div>Hey, Awesome Time:</div><div>{{ time }}</div>` }) export class AwesomeTimeComponent {time: string;constructor() {this.time = moment().format();} }其中 plain Component 沒有任何依賴,而 time Component 依賴于 moment.
moment 依賴的定義在 library 的 package.json 里:
{"name": "my-awesome-lib","version": "0.0.1","peerDependencies": {"@angular/common": "^8.2.14","@angular/core": "^8.2.14","moment": "^2.26.0"} }請注意,這些 peerDependencies 放在庫 my-awesome-lib 的范圍內,而不是放在單個模塊(庫內的文件)上。
最后,以下是在 my-awesome-lib/src/public-api.ts 下如何導出 awesome-plain 和 awesome-time:
export * from './awesome-plain/awesome-plain.component'; export * from './awesome-plain/awesome-plain.module'; export * from './awesome-time/awesome-time.component'; export * from './awesome-time/awesome-time.module';The problem: Client needs to install ALL peer dependencies from the library
上面這樣設計的問題是什么?
假設我們有一個 Angular 應用程序想要使用 my-awesome-lib。 客戶端應用程序(Angular 應用程序)需要做的第一件事是安裝庫:
npm i my-awesome-lib
安裝后,客戶端應用程序然后繼續導入和使用,例如只有 awesome-plain 組件。 這是客戶端應用程序中的代碼可能看起來很像:
// app.module.ts import { AwesomePlainModule } from 'my-awesome-lib'; @NgModule({...,imports: [...,AwesomePlainModule,],bootstrap: [AppComponent] }) export class AppModule {} // app.component.html <awesome-plain></awesome-plain>然而,ng serve 命令行會導致如下錯誤:
ERROR in ./node_modules/my-awesome-lib/fesm2015/my-awesome-lib.js Module not found: Error: Can’t resolve ‘moment’ in ‘/app-showcase-v8/node_modules/my-awesome-lib/fesm2015’
它說它找不到安裝在客戶端應用程序中的時刻。 嗯,這就是發生的事情。 盡管客戶端應用程序僅導入并使用 awesome-plain,但 Angular 編譯器仍會要求安裝 my-awesome-lib 中定義的所有 peerDependencies,這在本例中很重要。
如果客戶端應用程序同時使用 awesome-plain 和 awesome-time,當前情況可能會很好。 然而,想象一下,如果庫變大并且有不止 2 個模塊,假設有 10 個模塊。 讓我們再夸大一點; 如果 10 個模塊中有 5 個具有不同的 peerDependencies 會怎樣? 如果有一個客戶端應用程序使用這個庫并且只使用 1 個沒有任何 peerDependencies 的模塊,那么客戶端應用程序仍然需要安裝所有 5 個 peerDependencies! 當然,應該有比這更好的方法,對吧?
Enter the secondary entry points!
幸運的是,很有可能優化當前的方法。 到目前為止,庫中使用的方法僅使用稱為主要入口點的東西。 這由 package.json 文件表示,該文件僅存在于 my-awesome-lib/package.json 下,其中定義了整個庫的所有 peerDependencies。
通過二級入口點,我們可以進一步將 peerDependencies 拆分到庫級別之外; 它使得在庫內的文件夾或模塊中定義 peerDependencies 變得可行。
例如,通過將 awesome-time 設置為二級入口點,我們可以在子目錄中創建另一個 package.json 文件,該文件包含僅適用于 awesome-time 模塊的 peerDependencies。
因此,我們不再在庫級別定義 peerDependencies; 我們改為在
子目錄中定義它們。
此外,輔助入口點使我們能夠像下面這樣導入庫:
// Primary entry points import { AwesomePlainModule } from 'my-awesome-lib'; // Secondary entry points import { AwesomeTimeModule } from 'my-awesome-lib/awesome-time';這樣,如果 Client App 只使用 AwesomePlainModule,編譯器就不會再要求安裝 moment 了!
Implement secondary entry points
希望上面的解釋能讓大家對我們為什么要使用輔助入口點有一個大致的了解。
好消息是,實現二級入口點相當簡單明了,因為 ng-packagr 將在幕后完成大部分工作!
我們將使用 my-awesome-lib 作為以下實施指南的上下文。 在這種情況下,我們將設置 awesome-time 作為次要入口點,而 awesome-plain 將保持原樣(仍然是主要入口點)。
(1) Place the folders for secondary entry points directly under the library folder.
根據 ng-packagr 文檔,輔助入口點的文件夾布局示例之一是如下所示:
有趣的是,這是@angular/common 包中使用的類似文件夾布局,它以@angular/common 作為主要入口點,而@angular/common/testing 作為次要入口點。
文件夾結構如下:
(2) Create additional package.json and public-api.ts files in secondary entry points folder.
要創建輔助入口點,我們需要告訴 ng-packagr 要查找哪個文件夾。 這可以通過在 /my-awesome-lib/awesome-time 文件夾下創建另一個 package.json 和 public-api.ts 文件來實現,除了主入口點的文件。 僅通過這樣做,ng-packagr 將動態發現輔助入口點。
/my-awesome-lib/awesome-time/package.json 的內容可以是:
請注意,到目前為止,我們將 moment 作為 peerDependencies 放置在這里。 此外,“umdModuleIds”用于在構建庫時從 ng-packagr 中刪除警告。
以及 /my-awesome-lib/awesome-time/public-api.ts 的內容如下:
/** Public API Surface of my-awesome-lib/awesome-time*/ export * from './awesome-time.component'; export * from './awesome-time.module';(3) Remove secondary entry points peer dependencies from the main package.json and secondary entry point exported files from the main public-api.ts.
{"name": "my-awesome-lib","version": "0.0.1","peerDependencies": {"@angular/common": "^8.2.14","@angular/core": "^8.2.14"} }moment 包已被刪除,因為它已在 /my-awesome-lib/awesome-time/package.json 中定義。
此外,我們將刪除在主 my-awesome-lib/src/public-api.ts 中導出的 awesome-time 文件。 該文件現在應該只導出 awesome-plain 文件,如下所示:
/** Public API Surface of my-awesome-lib*/ export * from './awesome-plain/awesome-plain.component'; export * from './awesome-plain/awesome-plain.module';(4) Build the library.
現在一切都已設置完畢,我們現在可以嘗試通過執行命令 ng build my-awesome-lib 來構建庫。 如果正確完成,您應該在終端中看到以下內容:
另外,如果打開庫構建文件夾 dist/my-awesome-library,文件夾內應該還有一些名為 my-awesome-lib-awesome-time..js 的文件,例如 dist/fesm2015 和 dist/bundles . 如果將它與沒有輔助入口點的那個進行比較,構建文件夾通常只包含 my-awesome-lib..js,這是僅針對庫本身的構建。
(5) Install and import the library in the Client App.
最后一步是最終在 Angular 應用程序中使用它。 由于我們從主要入口點移動了 awesome-time,因此導入路徑會略有變化。 要在客戶端應用程序中使用新的庫文件夾結構,它應該如下所示:
// Primary entry points import { AwesomePlainModule } from 'my-awesome-lib'; // Secondary entry points import { AwesomeTimeModule } from 'my-awesome-lib/awesome-time';現在,如果客戶端應用程序只使用 AwesomePlainModule,我們應該可以在不安裝 moment 的情況下運行應用程序(僅在 AwesomeTimeModule 中使用)。
請記住,實施輔助入口點可能會導致您的 Angular 庫發生重大變化。 原因是因為使用您的庫的客戶端應用程序必須更新導入路徑。 否則,他們的應用程序將中斷,因為現在不再從“your-lib”導入輔助入口點文件。 因此,此更改不向后兼容。
Should there be any primary entry points at all? Is it okay to only have secondary entry points for the library?
您可能想知道,我們甚至應該使用主要入口點嗎? 在我看來,只有次要入口點是可以的,主要是因為@angular/material 只使用次要入口點。 另一方面,對于邏輯上相似的功能或特性,一般也建議使用主要入口點。 以下是在 Angular Package Format 文檔中編寫的:
Angular Package Format 的一般規則是為最小的邏輯連接代碼集生成 FESM 文件。 例如,Angular 包有一個用于@angular/core 的 FESM。 當開發人員使用來自@angular/core 的 Component 符號時,他們很可能也會直接或間接使用諸如 Injectable、Directive、NgModule 等符號。 因此,所有這些部分都應該捆綁到一個單一的 FESM 中。 對于大多數庫情況,應該將單個邏輯組組合到一個 NgModule 中,并且所有這些文件應該捆綁在一起作為包中的單個 FESM 文件,代表 npm 包中的單個入口點。
此外,就我而言,經驗法則是將某些模塊作為輔助入口點,如果它們具有不同的 peerDependencies。 這是為了防止客戶端應用程序被迫手動安裝所有依賴項,盡管它們并未使用所有依賴項。
Conclusions
總而言之,次要入口點是一個巧妙的功能,它允許我們進一步拆分 Angular 庫,尤其是在處理 peerDependencies 時。 它也很容易實現,因為 ng-packagr 將通過子目錄的 package.json 動態發現輔助入口點。
好處之一是它會減少客戶端應用程序被迫安裝所有依賴項的機會,即使該應用程序沒有導入/使用依賴于已安裝依賴項的任何庫函數。
更多Jerry的原創文章,盡在:“汪子熙”:
總結
以上是生活随笔為你收集整理的为什么我们需要给 Angular library 创建多重入口 multiple entry point的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 考试表情包搞笑图片大全
- 下一篇: tup股权激励什么意思