Angular7 Library庫的使用
創建 Angular 工作區
使用 –createApplication
這個 --createApplication 選項與 ng new 結合一起使用,設置它爲 false 時,它會告訴 ng new 命令不要在工作區內創建初始化的 Angular 應用。
爲了創建一個不包含初始化應用的 Angular 工作區,我們使用下面方法:
ng new module-library --createApplication=false
當你被詢問 router 選擇時,選擇默認 No 即可,css 選擇 less。
使用這個命令創建的 Angular 工作區,對比之前,工作區中的文件少了很多,儘管這個工作區顯得很“空”,它仍然包含有一些重要的配置信息:
package.json
包含了所有 Angular 所需的所有常見依賴
angular.json
不包含 projects 配置項的 Angular 配置文件
README.md, tsconfig.json, tslint.json
以及 node_modules
文件都與以前保持一致。
你可能會注意到,這裏沒有 src 文件夾,之後 projects 文件夾將會在生成庫項目或者測試應用項目時被添加。
自從我們設置 --createApplication 選項爲 false 後,我們的工程就不是一個初始化的應用。因此,如果你試着去運行一些命令,例如:ng build
或者 ng serve
時,我們會看到下面錯誤:Could not determine a single project for the ‘build’ target
。
庫項目
創建一個庫模塊
現在,我們有了 Angular 工作區,我們可以添加庫項目到工作區之中。
cd module-library
ng generate library module-library --prefix=ma
這個命令添加了一個 projects
目錄,幷包含有一個 module-library
子目錄,它就是我們新生成的 module-library Angular
庫。
注意到我們在命令中使用了 --prefix
標籤,其目的是讓庫組件變得更加有辨識度(注:就像 ng-zorro 所做的 nz-xxx
一樣)。如果我們不對其進行配置,Angular CLI 將使用 lib
作爲默認前綴標籤。
注意!在創建 Library 時總是顯示地使用 prefix
標籤進行配置。
以下是對於生成 Library 指令行爲結果的一個簡單總結:
-
在 angular.json 文件中爲我們的庫添加了一個新的 module-library 項目。
-
將 ng-packagr 的依賴項添加到 package.json 文件中。
-
在 tsconfig.json 文件中添加對 module-library 構建路徑的引用
-
在 projects/module-library 文件夾下創建庫的初始源代碼。
在 angular.json
文件中的 module-library
項目
查看 angular.json 文件會發現我們在 projects
對象下創建了一個名爲 module-library
的新項目。
"projects": {
"module-library": {
"root": "projects/module-library",
"sourceRoot": "projects/module-library/src",
"projectType": "library",
"prefix": "ma",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": {
"tsConfig": "projects/module-library/tsconfig.lib.json",
"project": "projects/module-library/ng-package.json"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "projects/module-library/src/test.ts",
"tsConfig": "projects/module-library/tsconfig.spec.json",
"karmaConfig": "projects/module-library/karma.conf.js"
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"projects/module-library/tsconfig.lib.json",
"projects/module-library/tsconfig.spec.json"
],
"exclude": [
"**/node_modules/**"
]
}
}
}
}
},
這裏需要注意一些關鍵元素:
-
root 其指向我們的庫項目的根文件夾。
-
sourceRoot 其指向我們的庫項目的源代碼位置。
projectType
其特別指出了這是一個 library 項目,而不像是其他兩個類型名稱爲 application 的應用項目。
prefix
這是將會用於我們的組件選擇器的前綴標識符。記得我們在創建庫時制定了 ma
作爲指定前綴。你可能熟悉 app 的前綴,其標識出哪些組件屬於主應用程序。
architect 此對象的內容用於指定 Angular CLI 如何處理項目的構建,測試和 lint
。值得注意的是,構建部分中的構建器使用了 ng-packagr
。
package.json
文件中的 ng-packagr
依賴項
在生成 Library 時 Angular CLI 需要 ng-packagr
這個包,因此他將其添加到了工作區的 package.json
文件中 devDependencies
依賴中。
"ng-packagr": "^3.0.0-rc.2"
在 tsconfig.json
文件中的構建路徑
當測試 module-library
時,我們希望能夠像日常使用的方式那樣引入他,而不是僅僅作爲整個應用中的一組文件。通常,當我們使用第三方庫時,我們使用 npm install 指令安裝,並將其安裝到我們的 node_modules
文件夾中。
即使在當前的情況下,module-library
不會安裝到 node_modules
文件夾中,但是他會被構建到工作區的 dist 文件夾下的某個子文件夾中。Angular CLI 將這個文件夾添加到 tsconfig.json
文件中,這樣 module-library
就可以像一個 Library 一樣以常見的方式被測試應用所引用了。 下述是在 tsconfig.json 文件中添加的路徑:
"paths": {
"module-library": [
"dist/module-library"
]
}
module-library
的源代碼
庫的 src 文件夾被包含在 projects/module-library
文件夾中。在庫中,Angular CLI 創建了一個包含服務和組件的新模塊。除此之外還包含了更多文件:
package.json
這是專門用於庫的 package.json
文件,也是庫作爲 npm 包發佈所使用的 package.json
文件。當用戶通過 npm 安裝庫時,該文件用於指定其依賴項。
public_api.ts
該文件作爲入口文件存在,他用於描述庫中哪個部分是外部可見的。我們需要在我們的入口文件中添加要導出的類以告知 ng-packagr 這個類應該暴露給使用庫的用戶。
ng-package.json
這是 ng-packagr
的配置文件。在 CLI 和 ng-packagr
沒有集成的時代我們需要儘可能地熟悉該文件的內容,但是現在,在擁有新版 Angular CLI 的情況下,我們只需要知道該文件是用於告知 ng-packagr
去哪找到入口文件以及去哪構建庫的內容即可。
創建測試應用項目
最後,我們希望建立一個測試應用項目,能夠調用我們建立的 Angular 庫。我們使用這個項目來做庫的測試或者文檔等工作。
ng generate application module-library-tester
這條命令,在 project 文件夾下添加了 module-library-tester
目錄。此外,Angular CLI 還添加了一個 module-library-tester-e2e
項目來用做 e2e 測試。
構建庫
使用下面的命令來構建 module-library 庫:
ng build module-library
向根目錄下的 package.json 文件夾中添加一個 build_lib 腳本:
"scripts": {
"build_lib": "ng build module-library"
},
現在我們可以通過 npm run build_lib
指令去構建庫了。
該命令會將庫構建於下述文件夾中:
module-library\dist\module-library
注意,從 v6.1 起,Angluar CLI 始終在生產模式下構建庫,所以不需要額外指定 --prod 選項。
與構建庫不同,構建一個應用,需要使用 --prod 選項:
ng build module-library-tester --prod
package.json
文件
在庫構建完成後,當前工作區內已經有3個 package.json
文件:
- 根目錄下的
package.json
文件
這個 package.json 是庫工作區的主package.json
文件。我們用該文件來列出主應用和庫都需要的依賴項。運行和構建主應用和庫所依賴的所有包都必須列舉在該文件中。
當我們在開發過程中使用 npm install
指令時,新加入的包將會添加到該文件中。
- 庫項目中的 package.json 文件
庫項目中的 package.json 文件位於projects\module-library
目錄下,其用於告知 ng-packagr 將什麼信息放入庫項目的發佈版 package.json 文件中。其 package.json 文件中有三個重要的部分需要注意:
1.名稱
這裏的名稱是指庫的名稱。未來如果某位用戶引入庫中的模塊,這個名稱就是出現在 from 部分內的引號中的名稱。舉例來說大概就是:
import { MALibraryModule } from 'module-library';
2.版本號
版本號對於庫而言格外重要,版本號能夠幫助用戶判斷他們是否在使用庫的最新版本。
3.依賴項
此項目中只包含用於運行庫所必須的依賴項。因此,你將會看到 dependencies
和 peerDependencies
,但是沒有 devDependencies
。
同樣應該在該 package.json
文件中添加那些常見的 npm 內容比如:License,作者,倉庫地址等。
值得注意的是,當使用 npm install 指令時,新安裝的包只會被添加到根目錄下的 package.json
文件中而不是在庫項目的 package.json
文件中。因此,當你安裝一個庫所需要的包時,你需要將包名稱手動添加到庫項目的 package.json
文件依賴項中。
4.庫的發佈版本 package.json
文件
當我們構建庫時庫的發佈版本 package.json 文件 由 ng-packagr 生成於 dist\module-library 文件目錄下。該 package.json 文件會隨着我們的庫一併發佈。
使用我們的庫的開發者將會使用 npm install 指令安裝該文件中所涉及的那些依賴項。
因爲發佈版本的 package.json 文件由 ng-packagr 生成,故而我們不應直接對其進行修改。如果你希望對發佈版本的 package.json 文件進行修改,需要更新 projects\module-library 目錄下的 庫項目的 package.json 文件。ng-packagr 以 庫項目的 package.json 文件爲基準去生成發佈版本的package.json 文件。
記住!永遠不要直接對發佈版本的 package.json 文件作出修改
5.打包庫
打包庫是指將生成的發佈文件進行打包以生成一個 tgz 文件用以手動分享或發佈於 npm。
使用 npm pack
指令在根目錄下的 package.json
文件中創建一個腳本,該腳本用於打包生成的庫。
"scripts": {
"npm_pack": "cd dist/module-library && npm pack"
},
現在我們只需要使用指令 npm run npm_pack
就可以完成對庫的打包。這條命令用於將文件目錄指向工作區的 dist 文件夾並執行 npm pack 指令,命令將會在同一目錄下生成一個形如 module-library-0.0.1.tgz
的包文件。
創造一個新的腳本包含 build_lib
和 npm_pack
兩個腳本的內容。將下述內容加入到主目錄下的 package.json 文件中的腳本對象中去:
"package": "npm run build_lib && npm run npm_pack"
現在看看主目錄下的 package.json 文件,和構建打包相關的腳本如下:
"scripts": {
"build_lib": "ng build module-library",
"npm_pack": "cd dist/module-library && npm pack",
"package": "npm run build_lib && npm run npm_pack"
},
注意,執行 package 腳本將會順序執行 build_lib 腳本 和 npm_pack 腳本。
使用如下指令完成對你的庫的構建和打包:
npm run package
package 腳本做了兩件事:
在 dist/module-library
目錄下構建了庫。
在同一目錄下使用 npm pack
指令將庫打包爲一個 npm 包,其形如:module-library-0.0.1.tgz
。
需要注意!即使生成的包是 tgz 文件,你也不能以 tgz 格式直接壓縮 dist 目錄作爲包,必須使用 npm pack
創建 tgz 文件。
擴展庫
以下是我們將要執行的步驟:
- 在庫中創造一個新的組件
- 將新添加的組件加入到庫模塊的 exports 屬性中
- 將新添加的組件加入到入口文件中
- 在執行完上述步驟後重新構建庫
在應用中使用新的組件
- 創建一個庫組件
- 當需要爲庫生成組件的時候我們需要使用 --project 標識來告訴 Angular CLI 在庫項目中生成組件。現在我們在庫裏生成一個簡單的組件並命名爲 list:
ng generate component list --project=module-library
-
現在我們的庫擁有了一個新的組件,並且 Angular CLI 將其添加到了庫模塊文件projects\module-library\src\lib\module-library.module.ts 的 declarations 屬性中。
-
將組件從庫的模塊中導出
將 ListComponent 添加到 module-library.module.ts 的 exports 數組中。而添加後的 MALibraryModule 文件應如下所示:
import { NgModule } from '@angular/core';
import { MALibraryComponent } from './module-library.component';
import { ListComponent } from './list/list.component';
@NgModule({
imports: [
],
declarations: [
MALibraryComponent,
ListComponent
],
exports: [
MALibraryComponent,
ListComponent
]
})
export class MALibraryModule { }
- 將組件添加到入口文件中
在用於定義庫 API 的入口文件projects\module-library\src\public_api.ts
中,添加以下內容以告知 ng-packagr 這個組件類應該暴露給使用庫的用戶:
export * from './lib/list/list.component';
- 現在 public_api.ts 入口文件應該像如下這樣:
/*
* Public API Surface of module-library
*/
export * from './lib/module-library.service';
export * from './lib/module-library.component';
export * from './lib/module-library.module';
export * from './lib/list/list.component';
- 重新構建庫
在對庫進行修改之後,我們需要重新構建庫:
ng build module-library
迄今維持我們所有的操作都是純手動的。事實上,Angular CLI 在 6.2 版本中增加了一個增量構建的功能。每當有文件發生了修改,Angular CLI 將會進行部分構建並拋出修改後的文件。使用這個新的觀察功能你只需要執行如下指令:
ng build module-library --watch
- 運行
我們無法直接運行一個庫項目,但可以運行創建的測試應用項目:
ng serve module-library-tester
- 測試
我們能夠爲創建的 Angular 庫項目和測試應用項目運行單元測試。
庫項目運行單元測試:
ng test module-library
測試應用項目運行單元測試:
ng test module-library-tester
在其他 Angular 應用中使用庫
安裝庫
- 希望在其他應用中使用庫的內容。我們需要執行以下指令:
npm install ../module-library/dist/module-library/module-library-0.0.1.tgz
- 引入庫模塊
我們首先需要向 App module 中添加庫的module和Http攔截器 。
爲此我們需要在 src\app\app.module.ts
文件中作出兩處修改:
引入 MALibraryModule
模塊和 HttpInterceptorService
import { MALibraryModule, HttpInterceptorService } from 'module-library';
將 MALibraryModule 模塊加入到 AppModule 的 imports 數組中,並用forRoot把environment引入庫中,給庫提供可配置的API地址。
現在 app.module.ts 應如下所示:
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { MALibraryModule, HttpInterceptorService } from 'module-library';
import { environment } from 'src/environments/environment';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
MALibraryModule.forRoot(environment)
],
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: HttpInterceptorService,
multi: true
}],
bootstrap: [AppComponent]
})
export class AppModule { }
使用一個庫中的組件
在應用中修改 AppComponent 組件的 html 模板文件並展示源自於庫的 list 組件。修改後的 app.component.html 文件如下所示:
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<ma-list></ma-list>
</div>