angular原理圖學習
安裝
npm install -g @angular-devkit/schematics-cli
建立原理圖
schematics blank --name=hello-world
執行原理圖
先執行npm run build
然後執行原理圖
schematics 資料夾地址:原理圖名稱 --<required-option>=<value>
demo
schematics .:hello-world // 可以看package.json 新增的檔案
schematics ./src/collection.json:hello-world
在執行一個命令, 創造一個新的原理圖
schematics blank --name=goodbye-world
collection.json
描述收集的原理圖的模式。每個原理圖都使用名稱、描述和工廠功能建立。
{ "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", "schematics": { "hello-world": { "description": "A blank schematic.", "factory": "./hello-world/index#helloWorld" }, "goodbye-world": { "description": "A blank schematic.", "factory": "./goodbye-world/index#goodbyeWorld" } } }
$schema
屬性指定 CLI 用於驗證的架構。
schematics
出了屬於該集合的命名原理圖。每個原理圖都有一個純文字描述,並指向主檔案中生成的入口函式。
該factory
屬性指向生成的入口函式。在本例中,您通過呼叫工廠函式來呼叫hello-world
原理圖。
#helloWorld
就是執行對應的helloWorld()
函式
下面兩個還不知道怎麼用
-
可選
schema
屬性指向一個 JSON 模式檔案,該檔案定義了可用於原理圖的命令列選項。- type:屬性提供的型別的描述符。
- properties:定義原理圖可用選項的物件。
-
可選
aliases
陣列指定一個或多個可用於呼叫原理圖的字串。例如,Angular CLI“generate”命令的原理圖有一個別名“g”,它允許你使用命令ng g
package.json匯入
{
"name": "my-lib",
"version": "0.0.1",
"schematics": "./src/collection.json",// 這個是為了知道原理圖從哪裡匯入的
}
新增一個js
schema.ts
export interface Schema {
name: string
}
import {Schema} from "./schema";
export function helloWorld(_options: Schema): Rule {
return (tree: Tree, _context: SchematicContext) => {
+ tree.create('hello.js',`console.log('Hello-World')`)
return tree;
};
}
helloWorld()
是原理圖入口函式, 是一個規則工廠,返回一個建立規則(Rule) 的高階函式Rule
: 定義一個函式, 接受一個Tree進行變換, 返回新的TreeTree
: 虛擬檔案系統,就是檔案SchematicContext
原理圖上下文, 每個原理圖都在自己的上下文中執行
執行
yarn build
在執行schematics .:hello-world
我們發現原理圖生成
hello.js
檔案, 但是現實中沒有, 就是原理圖在debug 模式下執行的當我們執行
schematics .:hello-world --debug=false
我們會發現生成了
hello.js
再執行這條命令, 我們發現控制帶會報錯, 我們必須刪除這個檔案才能執行
為了防止我們每次生成都要構建, 修改 package.json
"build:watch": "tsc -p tsconfig.json --watch",
建立 xxx/schema.json
{
"$schema": "http://json-schema.org/schema",
"$id": "SchematicsMyService",
"title": "My Service Schema",
"type": "object",
"description": "The name of the service.",
"properties": {
"name": {
"description": "The name of the service.",
"type": "string",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "輸入你需要執行的名稱?"
}
},
"required": [
"name"
]
}
匯入collection.json
"schematics": {
"hello-world": {
"description": "A blank schematic.",
"factory": "./hello-world/index#helloWorld",
+ "schema": "./hello-world/schema.json"
}
}
執行 schematics .:hello-world --debug=false
輸入名稱 xxx
檢查我們生成的 js檔案
使用原理圖模組
在./files/
資料夾下使用, 如果不用files
用template
必須在tsconfig.json
進行調整
__name@dasherize__
name
變數與正常字串的其餘部分分開
dasherize
是一個輔助函式,它將接收name
變數的值並將其轉換為 kebab case 字串,並且@
是將變數應用於輔助函式的一種方法。
name-age
===>name-age
classify
好像讓每一個首字母大寫
name-age
===>NameAge
camelize
首字母小寫,其他類似駝峰的形式
name-age
===>nameAge
<%= xxx %>
-
建立
hello-__name@dasherize__.ts
console.log('Hello <%= name %>')
import { Component } from '@angular/core'; @Component({ selector: 'hello-<%= dasherize(name) %>', }) export class Hello<%= classify(name) %>Component { console.log('Hello <%= name %>') }
-
index.ts
import {strings} from '@angular-devkit/core'; import {apply, mergeWith, Rule, SchematicContext, template, url} from '@angular-devkit/schematics'; import {Schema} from "./schema"; // You don't have to export the function as default. You can also have more than one rule factory // per file. export function helloWorld(_options: Schema): Rule { return (_, _context: SchematicContext) => { // const {name} = _options // tree.create('hello.js', `console.log('Hello-${name}')`) const sourceTemplates = url('./files'); const sourceParametrized = apply(sourceTemplates, [ template({ ..._options, ...strings }) ]) // return tree; return mergeWith(sourceParametrized) }; }
-
其實我們可以使用任意的自定義函式
import {Injectable} from '@angular/core'; import {Observable} from "rxjs"; import {HttpClient} from "@angular/common/http"; const API_URL = '/api/<%= dasherize(name) %>' @Injectable({ providedIn: 'root' }) // <%= classify(name) %> NameAge // <%= camelize(name) %> nameAge // <%= dasherize(name) %> name-age export class <%= classify(name) %>Service { constructor(private httpClient: HttpClient) { } findAll(): Observable<<%= classify(name) %>[]> { return this.httpClient.get<<%= classify(name) %>[]>(API_URL); } create(<%= camelize(name) %>: <%= classify(name) %>): Observable<number> { return this.httpClient.post<number>(API_URL, <%= camelize(name) %>); } } export interface <%= classify(name) %> { someProperty: string; }
-
執行命令
schematics .:hello-world name-age --debug=false
判斷 transform
schema.json
"properties": {
...
+ "transform": {
+ "type": "boolean",
+ "default": "false"
+ }
}
新增型別 schema.ts
export interface Schema {
name: string;
+ transform?:boolean;
}
使用
<% if(transform){ %>
let a=1
<% }else{ %>
let b=2
<% } %>
使用命令
schematics .:hello-world name-age true --debug=false
第二個引數的使用
上個完整點的案例
抄抄原始碼
https://github.com/angular/angular-cli/tree/main/packages/schematics/angular/component/files
新建一個__name@dasherize__
資料夾
__name@dasherize__.component.ts.template
檔案
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-<%= dasherize(name) %>',
templateUrl: './<%= dasherize(name) %>.component.html',
styleUrls: ['./<%= dasherize(name) %>.component.scss']
})
export class <%=classify(name)%>Component implements OnInit {
constructor() { }
ngOnInit() {
}
}
原理圖-資料夾下新建 schema.json
{
"$schema": "http://json-schema.org/schema",
"id": "componentSchema",
"title": "component options schema.",
"type": "object",
"descripiton": "建立一個component範本",
"properties": {
"name": {
"description": "component的名字.",
"type": "string",
"$default": {
"$source": "argv",
"index": 0
},
"x-prompt": "你想建立的component的名字:"
}
},
"required": [
"name"
]
}
id:這個模式定義在集合中的唯一 id。
title:一個人類可讀的模式描述。
type:由這些屬性提供的型別描述符。
properties:一個定義該原理圖可用選項的物件。
required:必填的選項注意屬性(proerties)選項:
$default 的設定,上面的表示,如果沒有指定輸入的選項,那麼輸入的第一個就是 name
x-prompt:如果沒有輸入選項,則提示語提示輸入
建立好 schema.json 之後,一定要記得在 collection.json 中配置 schema 屬性
"schematics": {
"hello-world": {
"description": "A blank schematic.",
"factory": "./hello-world/index#helloWorld",
+ "schema": "./hello-world/schema.json"
}
}
新建一個schema.ts
export interface Schema {
name: string;
}
編寫規則工廠邏輯程式碼
yarn add @schematics/angular -S
https://swmlee.com/2019/12/12/technicalessays/angular-schematics-tutorial/
https://github.com/angular/angular-cli/blob/main/packages/schematics/angular/component/index.ts
angular schematics 實現 ng add 指令安裝模組
抄原始碼一個完整的案例
schematics ./ng-hello/src/collection.json:c age --project=angualr12date1120
取消--project xxxx
就使用預設angular.json
中defaultProject
自帶的專案名
這裡介紹的一種schema.json
中引數的使用
打包到ng g
的命令裡
package.json
{
"name": "ng-hello",
"version": "0.0.0",
"description": "A blank schematics",
"scripts": {
"build": "tsc -p tsconfig.schematics.json",
"postbuild": "copyfiles package.json schematics/*/schema.json schematics/*/files/** schematics/collection.json ../dist/ng-hello/"
},
"keywords": [
"schematics"
],
"schematics": "./schematics/collection.json", // ng g xxx 找到的入口檔案是這個
"ng-add": {
"save": "devDependencies"
},
"devDependencies": {
"@types/node": "^12.11.1",
"@types/jasmine": "~3.10.0",
"jasmine": "^4.0.0",
"copyfiles": "file:../../node_modules/copyfiles",
"typescript": "file:../../node_modules/typescript"
}
}
../dist
注意對應打包生成的資料夾執行
yarn build
會自動跟著執行postbuild
指令執行,或者
"build:p": "tsc -p tsconfig.schematics.json & npm run postbuild",
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-one/schematics",// 打包後的出口檔案
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"target": "es6",
"types": [
"jasmine",
"node"
]
},
"include": [
"schematics/**/*"
],
"exclude": [
"schematics/*/files/**/*"
]
}
然後把ng-hello
包丟到node_modules
裡面
執行ng g ng-hello:xxx
執行命令
其實我們也可以執行生成打包丟到node_modules
裡面然後執行使用
記得別用
src
資料夾, 要schematincs
資料夾 這樣就跟 ng g 的保持一致
測試的時候到最外層的package.json上, 因為要用到
angular.json
schematics ./ng-hello/schematics/collection.json:c age
/**
* 構建用於生成的預設專案路徑。
* @param專案將生成其預設路徑的專案。
*/
export function buildDefaultPath(project: workspaces.ProjectDefinition): string {
const root = project.sourceRoot ? `/${project.sourceRoot}/` : `/${project.root}/src/`;
const projectDirName =
project.extensions['projectType'] === ProjectType.Application ? 'app' : 'lib';
return `${root}${projectDirName}`;
}
// 如果沒有執行path就是用預設的,project是angular.json裡面的, 如果預設指令--project的名稱就使用預設的
// project.sourceRoot 預設是`src` 所以 root 是 /src/
// 所有我們知道最後輸入的是 /src/app
export enum ProjectType {
Application = 'application',
Library = 'library',
}
--style less
找到對應的模組find-module.ts
對應的程式碼
https://github.com/973782523/angualr-schematics
如果在vue使用
npm install @angular/cli -D
yarn add typescript copyfiles -D
記得在src
新增一個資料夾app
或者你在angualr.json
修改app
改成你對應的檔案
cd ng-hello
// 打包ts
yarn build-watch2
// 打包其他檔案
yarn build:p 每次修改程式碼的時候,記得執行這個命令進行測試
ng g ng-hello:c age1 --skip-import
寫了一個vue的案例
https://github.com/973782523/vue3-schematics