Angular 17+ 高階教程 – Library

兴杰發表於2024-04-13

前言

當你需要管理超過一個專案時,你就需要知道怎麼使用 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

有兩個小區別:

  1. $schema 路徑多了一個 ../

  2. 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+ 高階教程 – 目錄

相關文章