起步
當建立 Angular 庫時,你可以為同時為它打包進一組原理圖,並把它與 Angular CLI 整合在一起。藉助原理圖,使用者可以用 ng add 來安裝你這個庫的初始版本,可以用 ng generate 來建立你在庫中定義的一些工件,可以用 ng update 來調整他們的專案,以支援你在庫的新版本中引入的重大變更。
建立一個angular庫
ng new demo --create-application=false
ng g library my-lib
可見如下目錄結構
├── node_modules/
├── projects
│ └── my-lib
│ ├── src
│ │ ├── lib
│ │ ├── public-api.ts
│ │ └── test.ts
│ ├── karma.conf.js
│ ├── ng-package.json
│ ├── package.json
│ ├── README.md
│ ├── tsconfig.lib.json
│ ├── tsconfig.lib.prod.json
│ ├── tsconfig.spec.json
│ └── tslint.json
├── README.md
├── package.json
├── .editorconfig
├── angular.json
├── tsconfig.base.json
├── tslint.json
└── tsconfig.json
新增projects/my-lib/schematics/collection.json檔案
{
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"ng-add": {
"description": "Add my library to the project.",
"factory": "./ng-add/index#ngAdd"
}
}
}
修改projects/my-lib/package.json檔案
{
"name": "my-lib",
"version": "0.0.1",
"schematics": "./schematics/collection.json",
}
新增projects/my-lib/schematics/ng-add/index.ts檔案
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
import { strings } from '@angular-devkit/core';
// Just return the tree
export function ngAdd(options: any): Rule {
return (tree: Tree, context: SchematicContext) => {
context.addTask(new NodePackageInstallTask());
// 如果不是 Angular 專案則丟擲錯誤
const workspaceConfig = tree.read('angular.json');
if (!workspaceConfig) {
throw new SchematicsException('Not an Angular CLI workspace');
}
const templateSource = apply(url('./files'), [
applyTemplates({
...strings
}),
move(normalize('')),
]);
return chain([mergeWith(templateSource)]);
};
}
新增projects/my-lib/schematics/ng-add/files 檔案
└── files
└──index.ts
index.ts內容如下
// #docregion template
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class <%= classify(name) %>Service {
constructor(private http: HttpClient) { }
}
定義依賴型別,在projects/my-lib/package.json中新增
"ng-add": {
"save": "devDependencies"
}
修改projects/my-lib/tsconfig.schematics.json
{
"compilerOptions": {
"baseUrl": ".",
"lib": [
"es2018",
"dom"
],
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"rootDir": "schematics",
"outDir": "../../dist/my-lib/schematics",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"target": "es6",
"types": [
"jasmine",
"node"
]
},
"include": [
"schematics/**/*"
],
"exclude": [
"schematics/*/files/**/*"
]
}
屬性 | 說明 |
---|---|
rootDir | 指出在你的 schematics/ 資料夾中包含要編譯的輸入檔案。 |
outDir | 對映到了庫的輸出目錄下。預設情況下,這是工作空間根目錄下的 dist/my-lib 資料夾 |
修改projects/my-lib/package.json
{
"name": "my-lib",
"version": "0.0.1",
"scripts": {
"build": "../../node_modules/.bin/tsc -p tsconfig.schematics.json",
"copy:files": "cp --parents -p -r schematics/*/files/** ../../dist/my-lib/",
"copy:collection": "cp schematics/collection.json ../../dist/my-lib/schematics/collection.json",
"postbuild":"npm run copy:files && npm run copy:collection"
},
"peerDependencies": {
"@angular/common": "^7.2.0",
"@angular/core": "^7.2.0"
},
"schematics": "./schematics/collection.json",
"ng-add": {
"save": "devDependencies"
}
}
屬性 | 說明 |
---|---|
build | 指令碼使用自定義的 tsconfig.schematics.json 檔案來編譯你的原理圖。 |
copy | *語句將已編譯的原理圖檔案複製到庫的輸出目錄下的正確位置,以保持目錄的結構。 |
postbuild | 指令碼會在 build 指令碼完成後複製原理圖檔案。 |
修改根目錄下的package.json,在scripts下加入
"build": "ng build my-lib --prod && cd ./projects/my-lib && npm run build",
"publish": "cd ./dist/my-lib && npm publish"
補充:
建立 schema.d.ts,定義的各個選項的值
一般的,可以手動建立 schema.d.ts,如本生成 component 的原理圖,它的 schema.json 中屬性只有一個必填的 name,那麼編寫的 schema.d.ts 內容就如下:
export interface Schema {
name: string;
}
實際上,這個檔案可以使用指令生成,在 schema.json 的同級目錄下,開啟終端輸入指令,如下:
npx -p dtsgenerator dtsgen schema.json -o schema.d.ts
開始釋出
npm publish
試一試ng add吧!
使用schematics修改專案
如何使用schematics修改專案中的package.json
方法 |
說明 |
---|---|
tree.overwrite() | 重新編排package.json |
tree.read() | 讀取檔案內容 |
修改projects/my-lib/schematics/ng-add/index.ts
//讀取angular.json的檔案內容
const workspaceConfig = tree.read('angular.json');
// 如果不是 Angular 專案則丟擲錯誤
if (!workspaceConfig) {
throw new SchematicsException('Not an Angular CLI workspace');
}
// 讀取package.json的檔案內容
const workspaceJson = tree.read('package.json');
let json=JSON.parse(workspaceJson)
json.script.hello="print('123')"
tree.overwrite('./package.json',JSON.stringify(json))
在node_modules新增引入與注入項
方法 | 說明 |
---|---|
addImportToModule(source: ts.SourceFile, modulePath: string, classifiedName: string, importPath: string): Change[] | 新增引入到module |
ts.createSourFile | 建立資原始檔 |
import * as ts from '@schematics/angular/third_party/github.com/Microsoft/TypeScript/lib/typescript';
import { addImportToModule } from '@schematics/angular/utility/ast-utils';
......
const modulePath = `/app.module.ts`;
const sourText = _tree.read(modulePath).toString('utf-8');
const sourceFile = ts.createSourceFile(modulePath, sourceText, ts.ScriptTarget.Latest, true);
const importPath = '@fortawesome/angular-fontawesome';
const moduleName = 'FontAwesomeModule'; //檔名為駝峰命名
const declarationChanges = addImportToModule(sourceFile, modulePath, moduleName, importPath);
const declarationRecorder = _tree.beginUpdate(modulePath);
for (const change of declarationChanges) {
if (change instanceof InsertChange) {
declarationRecorder.insertLeft(change.pos, change.toAdd);
}
}
_tree.commitUpdate(declarationRecorder);
更新檔案
方法 | 說明 |
---|---|
tree.beginUpdate() | 更新內容 |
const htmlPath = `./app/src/app.component.html`;
const htmlStr = `\n\n`;
const modulePath = `/app.module.ts`;
const sourText = _tree.read(htmlPath).toString('utf-8');
const htmlSourceFile = ts.createSourceFile(htmlPath, sourceText, ts.ScriptTarget.Latest, true);
const htmlRecorder = _tree.beginUpdate(htmlPath);
htmlRecorder.insertLeft(htmlSourceFile.end, htmlStr);
_tree.commitUpdate(htmlRecorder);
package.json依賴項安裝
方法 | 說明 |
---|---|
addPackageToPackageJson | 新增依賴支援 |
import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
......
const dependencies = [{ name: '@fortawesome/fontawesome-svg-core', version: '~1.2.25' }],
addPackageToPackageJson(
_tree,
dependency.name, //依賴包名
dependency.version,//版本
);
ng Update使用
在collection.json 同級目錄,新建 migration.json 檔案,並寫入以下內容:
{
"$schema": "../../../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"migration002": {
"version": "0.0.2",
"description": "更新angular-schematics-tutorial到0.0.2版本時執行的更新",
"factory": "./ng-update/index#update"
}
}
}
在 package.json 中宣告 ug-update 配置
在 package.json 中,新增以下專案:
"ng-update": {
"migrations": "./schematics/migration.json"
},
其作用,就是在執行 ng update 時,能夠找到對應的配置檔案
在projects/my-lib/schematics/ 目錄下新建index.ts
import { Rule, Tree, SchematicContext, SchematicsException } from '@angular-devkit/schematics';
import { buildDefaultPath } from '@schematics/angular/utility/project';
import * as ts from 'typescript';
export function update(): Rule {
return (_tree: Tree, _context: SchematicContext) => {
// 解析angular專案
const workspaceConfigBuffer = _tree.read('angular.json');
if (!workspaceConfigBuffer) {
throw new SchematicsException('Not an Angular CLI workspace');
}
return tree.create('index.md','我更新了')
}
}
完結撒花!!