前言
當你需要管理超過一個專案時,你就需要知道怎麼使用 Angular Library。
你可以把多個專案共享的元件放到這個 Library 了,就像 Angular Material 那樣。
參考
Sandro Roth – Building an Angular Library with multiple entry points (主要參考)
Docs – Creating libraries
Docs – Copy assets
Docs – Embed assets in CSS
Stack Overflow – Include assets when building angular library
Angualr Library の Get Started 版
我們先來一個 Get Started 版本,之後再補一個實戰版。
提醒:我這裡給的例子 Library 和 Application 會在同一個專案裡 (所謂的 Local Library)。如果要不同專案,那就需要把 Library 釋出到 npm 才行。在本篇的結尾會講解如何 publish to npm。
Create project
ng new play-library --create-application=false
在建立專案的同時,不要建立 Application 先,因為有 Library,folder 結構會不一樣。
目前 folder 結構長這樣
angular.json 長這樣
空空如也。
Create Application
接著建立 Application
ng g app my-app --routing=false --ssr=false --style=scss --skip-tests
folder 多了一個 projects/my-app
angular.json 也多了一個 projects.my-app 配置
Create Library
接著建立 Library
ng g lib stooges --prefix=stg
我的 Library 名字叫 stooges
folder 又多了一個 projects/stooges
stooges library 裡,Angular 預設會替我們建立一個 demo component 和 service。
angular.json 也多了一個 projects.stooges 配置
Build library
要使用 Library ,我們需要先 build 它。
ng build stooges --watch
build 也是可以 watch 的哦,每當我們修改,它就會 re-build (我不清楚是 re-build 修改的部分還是全部🤷♂️)
build 好之後,它會多一個 folder -- dist/stooges
Use library in application
app.component.ts
import { Component } from '@angular/core'; import { StoogesComponent } from 'stooges'; // 1. import component from library @Component({ selector: 'app-root', standalone: true, imports: [StoogesComponent], // 2. import StoogesComponent templateUrl: './app.component.html', styleUrl: './app.component.scss' }) export class AppComponent {}
app.component.html
<stg-stooges />
run
ng serve --open
效果
哎喲,不錯哦!It just work😎。
The connection between the library and the application
你可能會好奇,app.component.ts 為什麼可以 import 到 'stooges'
import { StoogesComponent } from 'stooges';
stooges library 在 dist 裡,並不在 node_modules 裡丫🤔。
它的秘密在 tsconfig.json 裡
在 ng g lib 時,它偷偷往裡頭做了一個 connection 配置,所以 Application 就和 Library 連上了。
總結
Get Started 只是讓大家感受以下 Angular Library 長啥樣,上面提到的幾個 folder 和 file 都是和 Library 比較有關係的,如果以後遇到什麼疑難雜症可以多往這幾個地方調查。
好,我們進入下一 part -- Angualr Library 實戰版。
Angualr Library の 實戰版
我們延續上面 Get Started 版本,把它改成實戰版。
Multiple export path
目前有一個問題 -- Library 只有一個出入口
import { StoogesComponent } from 'stooges';
假如我有 1000 個元件,由於它們都是透過 import .. from 'stooges' 匯入,那它們就絕對不可以撞名字。
這對命名要求很高啊。
那...如果可以這樣...
import { StgDialogComponent, StgSameNameComponent as StgDialogSameNameComponent } from 'stooges/dialog';
import { StgCardComponent, StgSameNameComponent as StgCardSameNameComponent } from 'stooges/card';
stooges/table 和 stooges/select 都是 stooges library,但 stooges library 裡面又細分成了 2 個 namespace 'table' 和 'select'。
我們可以以 2 個不同的 path 做 import,這樣就大大減少了撞名字的可能性,即使撞了名字也可以透過 as alias 換名。
restructure folder
首先,把 src/lib/ folder 給刪了。
改成這樣
select 和 table 將成為 2 個 export path,它們裡面裝了很多元件,細節我們下面再看。
index.ts 取代了原本的 src/public_api.ts
由於我沒有需要 root export (因為有了 select 和 table 2 個 sub export),所以這裡做一個假 export 騙過它就好。
接著,ng-package.json 的路徑需要換一下
然後是 table 和 select folder
每一個要 sub export 的 folder 都需要加上 index.ts 和 ng-package.json。
index.ts 負責 export 元件
ng-package.json 就抄 root 的 ng-package.json
有兩個小區別:
-
$schema 路徑多了一個 ../
-
root 有一個 "dest" : "../../dist/stooges" 屬性,sub 不需要 "dest" 屬性。
select 和 table 一樣,也需要 index.ts 和 ng-package.json。
build library
接著 build library
ng build stooges --watch
效果
之前只有一個 lib folder,現在變成了 select 和 table 2 個 folders。
connect library
connect library 會比之前複雜一些。
首先是 tsconfig.ts
本來是直接連結到 dist library,現在改成連結到原本的 source library,然後結尾要用 /* 表示匹配 multiple path。
接著是 angular.json
把 /src 移除
再來是 /projects/my-app/tsconfig.app.json
這裡連結到 dist library,之前 root tsconfig 則是連結到 source library,一個 dist 一個 source 被搞錯哦。
test run application
build and connect 之後就可以 test run 了。
app.component.ts
import { Component } from '@angular/core'; import { StgSelectModule } from 'stooges/select'; // 1. import component from library import { StgTableModule } from 'stooges/table'; // 2. import component from library @Component({ selector: 'app-root', standalone: true, imports: [StgSelectModule, StgTableModule], templateUrl: './app.component.html', styleUrl: './app.component.scss' }) export class AppComponent {}
兩個 module 分別 import from 各自的 path。
app.component.html
<stg-table> <stg-tr> <stg-td /> <stg-td /> </stg-tr> </stg-table> <stg-select> <stg-option /> <stg-option /> </stg-select>
run
ng serve --open
效果
import sub path inside library
library 內如果需要互相 import,也是使用絕對路徑。
Export scss
除了 multiple export path,另一個常見的需求是要 export scss。
首先在 library 裡建立一個 styles forlder
reset.scss 和 _theme.scss
新增 assets 配置到 ng-package.json
表示我們要 export styles 這個 folder 裡的所有 scss。
build library
ng build stooges --watch
效果
_theme.scss 和 reset.scss 被打包出來了。
connect library
新增 stylePreprocessorOptions 到 angular.json
這樣 application 就能連結到 dist library 的 styles 了。
test run application
run
ng serve --open
效果
margin 被 reset.scss 清除了,body background 也被 theme.scss 染成了粉紅色。
Export assets
scss 可以 export,其它型別的 file 也可以 export,比如圖片,雖然圖片不常會被封裝進 Library。
新增 assets folder 到 Library
裡面有一張圖片。
在 ng-package.json 裡再新增多一個 assets 配置
意思是我們要 export 所有 assets 裡的 files。
build library
ng build stooges --watch
效果
圖片被打包出來了。
connect library
到 angular.json 新增 assets 配置
這樣 application 就連結上了 dist library 的 assets files。
test run application
app.component.html
path starts with /stg-assets/**/* (使用絕對路徑)
run
ng serve --open
效果
use assets inside library
假設,我們沒有 export assets,但是我們有 assets,我們只是在 library 中使用它。
這種情況的話,假如圖片用於 scss url('....') 那它會被自動 convert to base64,我們可以不需要做 export。
假如圖片被用於 <img src="..." >,這樣不行,它不會自動 convert to base64,我們一定要 export assets 才行。
另外,有 export 的必須使用絕對路徑,如果 url('...') 使用相對路徑那它會 convert to base64,如果使用絕對路徑則不會 convert to base64 (使用絕對路徑,我們就要確保有 export 圖片哦,不然就空白了)。
總結
它其實就是幾個東西在玩。
首先是 library folder 結構
然後是 library 要 export 的配置
接著 build to dist
然後 application 要 connect to dist library 或者 souce library
ts, scss, assets 三個的 export 和 connect 配置都不太一樣。
大概就是這些,建議大家自己動手玩一玩。
Publish Library
publish 很簡單,因為我們已經 build to dist 了,把整個 dist folder 釋出到 npm 就可以了。
cd dist/stooges
npm publish
publish 好了後就可以下載了
yarn add stooges
接著需要把 connect to dist 換成 connect to node_modules。
首先,root tsconfig 不需要 connect to source library 了,因為 node_modules 裡的 ts 是自動 connect 的。
同樣,application 的 tsconfig 也不需要 connect to dist library 了
ts 不需要配置,但是 scss 和 assets 需要。
去 angular.json 把 connect to dist 換成 connect to node_modules
搞定!
關於 peerDependencies
Library 或許會依賴其它的 Library,通常這些依賴不會寫在 package.json 的 dependencies,而會寫在 peerDependencies。
它們的區別是,peerDependencies 要求使用 Library 的人在外部去 yarn add 這些 Library 依賴,好處是不會 duplicated,因為 Application 和 Library 或許有相同的依賴,總不能 2 邊分開載入,是吧。
目錄
上一篇 Angular 17+ 高階教程 – EventManagerPlugin & Hammer.js Gesture
下一篇 Angular 17+ 高階教程 – Prettier, ESLint, Stylelint
想檢視目錄,請移步 Angular 17+ 高階教程 – 目錄