What are Angular Schematics? How to develop your Angular Schematics locally? The following article will give you a detailed introduction and use an example to get better familiar with it. I hope it will be helpful to you!
Angular Schematics is a template-based, Angular-specific code generator. Of course, it not only generates code, it can also modify our code. It allows us to implement our code based on Angular CLI. Some automated operations of my own. [Related tutorial recommendations: "angular tutorial"]
I believe that everyone has used ng generate component component-name
, ## while developing Angular projects. #ng add @angular/materials,
ng generate module module-name, these are some CLIs that have been implemented for us in Angular, so how should we implement them in our own projects based on our own What about the project's CLI? This article will be introduced based on our practice in
ng-devui-admin. We welcome your continued attention. We will launch a richer CLI in the future to help you build an Admin page faster.
schematics Scaffolding
npm install -g @angular-devkit/schematics-cli # 安装完成之后新建一个schematics项目 schematics blank --name=your-schematics
shematics project.
tsconfig.json: Mainly related to project packaging and compilation, not here Give a detailed introduction
collection.json: related to your CLI command, used to define your related commands
{ "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", "schematics": { "first-schematics": { "description": "A blank schematic.", "factory": "./first-schematics/index#firstSchematics" } } }
first-schematics: The name of the command, which can be run in the project via
ng g first-schematics:first-schematics.
description: Description of this command.
factory: Entry function for command execution
There is usually another attribute
schema, which we will explain later.
: Implement the relevant logic of your command in this file
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics'; export function firstSchematics(_options: any): Rule { return (tree: Tree, _context: SchematicContext) => { return tree; }; }
tree: Here you can understand tree as our entire angular project. You can add files, modify files, and delete files through tree.
_context: This parameter is the context in which
schematics is run. For example, you can execute
npm install through
context.
Rule: The operation logic formulated for us.
ng-add directive.
New command-related files<span style="font-size: 18px;"></span>
First we create a new directory under thesrc directory
ng-add , and then add three files
index.ts,
schema.json,
schema.ts in the directory. After that, your directory structure should be as follows :
##Configurationcollection.json<span style="font-size: 18px;"></span>
Then we configure this command in
: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
...,
"ng-add": {
"factory": "./ng-add/index",
"description": "Some description about your schematics",
"schema": "./ng-add/schema.json"
}
}
}</pre><div class="contentsignin">Copy after login</div></div>
in <span style="font-size: 18px;"></span>files<span style="font-size: 18px;"></span>Add the file we want to insert into the directory
<span style="font-size: 18px;"></span>For the syntax of
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:html;toolbar:false;"><div class="my-app">
<% if (defaultLanguage === &#39;zh-cn&#39;) { %>你好,Angular Schematics!<% } else { %>Hello, My First Angular Schematics!<% } %>
<h1>{{ title }}</h1>
</div></pre><div class="contentsignin">Copy after login</div></div>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">.app {
display: flex;
justify-content: center;
align-item: center;
}</pre><div class="contentsignin">Copy after login</div></div>
<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">import { Component } from &#39;@angular/core&#39;;
@Component({
selector: &#39;app-root&#39;,
templateUrl: &#39;./app.component.html&#39;,
styleUrls: [&#39;./app.component.scss&#39;]
})
export class AppComponent {
title = <% if (defaultLanguage === &#39;zh-cn&#39;) { %>&#39;你好&#39;<% } else { %>&#39;Hello&#39;<% } %>;
}</pre><div class="contentsignin">Copy after login</div></div>
Start implementing the command logic<span style="font-size: 18px;"></span>
{ "$schema": "http://json-schema.org/schema", "id": "SchematicsDevUI", "title": "DevUI Options Schema", "type": "object", "properties": { "defaultLanguage": { "type": "string", "description": "Choose the default language", "default": "zh-cn", "x-prompt": { "message": "Please choose the default language you want to use: ", "type": "list", "items": [ { "value": "zh-cn", "label": "简体中文 (zh-ch)" }, { "value": "en-us", "label": "English (en-us)" } ] } }, "i18n": { "type": "boolean", "default": true, "description": "Config i18n for the project", "x-prompt": "Would you like to add i18n? (default: Y)" } }, "required": [] }
, i18n
, we use defaultLanguage
Take an example to explain the related configuration of parameters: <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:js;toolbar:false;">{
"defaultLanguage": {
"type": "string",
"description": "Choose the default language",
"default": "zh-cn",
"x-prompt": {
"message": "Please choose the default language you want to use: ",
"type": "list",
"items": [
{
"value": "zh-cn",
"label": "简体中文 (zh-ch)"
},
{
"value": "en-us",
"label": "English (en-us)"
}
]
}
}
}</pre><div class="contentsignin">Copy after login</div></div><p><code>type
代表该参数的类型是 string
。default
为该参数的默认值为 zh-cn
。x-prompt
定义与用户的交互,message
为我们对用户进行的相关提问,在这里我们的 type
为 list
代表我们会为用户提供 items
中列出的选项供用户进行选择。
schema.ts
:在该文件中定义我们接收到的参数类型export interface Schema { defaultLanguage: string; i18n: boolean; }
index.ts
:在该文件中实现我们的操作逻辑,假设在此次 ng-add
操作中,我们根据用户输入的 defaultLanguage
, i18n
来对用户的项目进行相应的更改,并且插入相关的 npm 包,再进行安装。import { apply, applyTemplates, chain, mergeWith, move, Rule, SchematicContext, SchematicsException, Tree, url } from '@angular-devkit/schematics'; import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks'; import { Schema as AddOptions } from './schema'; let projectWorkspace: { root: string; sourceRoot: string; defaultProject: string; }; export type packgeType = 'dependencies' | 'devDependencies' | 'scripts'; export const PACKAGES_I18N = [ '@devui-design/icons@^1.2.0', '@ngx-translate/core@^13.0.0', '@ngx-translate/http-loader@^6.0.0', 'ng-devui@^11.1.0' ]; export const PACKAGES = ['@devui-design/icons@^1.2.0', 'ng-devui@^11.1.0']; export const PACKAGE_JSON_PATH = 'package.json'; export const ANGULAR_JSON_PATH = 'angular.json'; export default function (options: AddOptions): Rule { return (tree: Tree, context: SchematicContext) => { // 获取项目空间中我们需要的相关变量 getWorkSpace(tree); // 根据是否选择i18n插入不同的packages const packages = options.i18n ? PACKAGES_I18N : PACKAGES; addPackage(tree, packages, 'dependencies'); // 执行 npm install context.addTask(new NodePackageInstallTask()); // 自定义的一系列 Rules return chain([removeOriginalFiles(), addSourceFiles(options)]); }; }
下面时使用到的函数的具体实现:
// getWorkSpace function getWorkSpace(tree: Tree) { let angularJSON; let buffer = tree.read(ANGULAR_JSON_PATH); if (buffer) { angularJSON = JSON.parse(buffer.toString()); } else { throw new SchematicsException( 'Please make sure the project is an Angular project.' ); } let defaultProject = angularJSON.defaultProject; projectWorkspace = { root: '/', sourceRoot: angularJSON.projects[defaultProject].sourceRoot, defaultProject }; return projectWorkspace; }
// removeOriginalFiles // 根据自己的需要选择需要删除的文件 function removeOriginalFiles() { return (tree: Tree) => { [ `${projectWorkspace.sourceRoot}/app/app.component.ts`, `${projectWorkspace.sourceRoot}/app/app.component.html`, `${projectWorkspace.sourceRoot}/app/app.component.scss`, `${projectWorkspace.sourceRoot}/app/app.component.css` ] .filter((f) => tree.exists(f)) .forEach((f) => tree.delete(f)); }; }
将 files 下的文件拷贝到指定的路径下,关于 chain
, mergeWith
, apply
, template
的详细使用方法可以参考 Schematics
// addSourceFiles function addSourceFiles(options: AddOptions): Rule { return chain([ mergeWith( apply(url('./files'), [ applyTemplates({ defaultLanguage: options.defaultLanguage }), move(`${projectWorkspace.sourceRoot}/app`) ]) ) ]); }
// readJson function readJson(tree: Tree, file: string, type?: string): any { if (!tree.exists(file)) { return null; } const sourceFile = tree.read(file)!.toString('utf-8'); try { const json = JSON.parse(sourceFile); if (type && !json[type]) { json[type] = {}; } return json; } catch (error) { console.log(`Failed when parsing file ${file}.`); throw error; } } // writeJson export function writeJson(tree: Tree, file: string, source: any): void { tree.overwrite(file, JSON.stringify(source, null, 2)); } // readPackageJson function readPackageJson(tree: Tree, type?: string): any { return readJson(tree, PACKAGE_JSON_PATH, type); } // writePackageJson function writePackageJson(tree: Tree, json: any): any { return writeJson(tree, PACKAGE_JSON_PATH, json); } // addPackage function addPackage( tree: Tree, packages: string | string[], type: packgeType = 'dependencies' ): Tree { const packageJson = readPackageJson(tree, type); if (packageJson == null) { return tree; } if (!Array.isArray(packages)) { packages = [packages]; } packages.forEach((pck) => { const splitPosition = pck.lastIndexOf('@'); packageJson[type][pck.substr(0, splitPosition)] = pck.substr( splitPosition + 1 ); }); writePackageJson(tree, packageJson); return tree; }
为了保持 index.ts
文件的简洁,可以将相关操作的方法抽取到一个新的文件中进行引用。
测试 <span style="font-size: 18px;">ng-add</span>
至此我们已经完成了 ng-add
命令,现在我们对该命令进行测试:
ng new test
初始化一个 Angular 项目cd test && mkdir libs
在项目中添加一个 libs 文件夹,将图中标蓝的文件拷贝到其中npm link libs/
cd libs && npm run build && cd ..
ng add first-schematics
之后会看到如下提示npm start
来查看执行的结果如下综上简单介绍了一个 Schematics
的实现,更多的一些应用欢迎大家查看 ng-devui-admin 中的实现。
更多编程相关知识,请访问:编程学习!!
The above is the detailed content of What are Angular Schematics? How to build? (detailed explanation). For more information, please follow other related articles on the PHP Chinese website!