angular 原理图(Schematic)的学习笔记
<h2 id="介绍">介绍</h2><h4 id="schematics-是什么">Schematics 是什么?</h4>
<p>Schematics 是现代前端开发工作流的工具;它可以将变化应用到你的项目中。比如创建一个组件、添加配置项、将框架添加到现有项目,或者更新你的代码来修复更新依赖时带来的 break change。</p>
<p>Schematics — AnIntroduction<br>
有道云链接</p>
<h2 id="起步">起步</h2>
<h4 id="首先需要安装全局依赖">首先需要安装全局依赖</h4>
<pre><code>$ npm i @angular-devkit/schematics-cli -g
</code></pre>
<h4 id="执行schematics指令-看到如下信息则安装成功">执行<code>schematics</code>指令 看到如下信息则安装成功</h4>
<p><img src="https://img2020.cnblogs.com/blog/2196055/202011/2196055-20201104095807448-1791725060.png" alt="image" loading="lazy"></p>
<h4 id="之后使用下面的命令新建一个-scheamtics-项目并用编辑器打开">之后使用下面的命令新建一个 scheamtics 项目并用编辑器打开</h4>
<pre><code>$ schematics schematic --name my-schematics
$ cd my-schematics
$ code .
</code></pre>
<h4 id="目录结构">目录结构</h4>
<pre><code>├── node_modules/ // 依赖包
├── src
│ ├── my-full-schematic // 单个schematic文件夹
│ │ ├── files // 要复制的可选组件/模板文件。
│ │ │ ├── test__INDEX__
│ │ │ └── test2
│ │ ├── index_spec.ts
│ │ ├── index.ts //定义命名原理图中转换逻辑的代码。
│ │ └── schema.json //原理图变量定义
│ ├── my-other-schematic
│ │ ├── index_spec.ts
│ │ └── index.ts
│ ├── my-schematic
│ │ ├── index_spec.ts
│ │ └── index.ts
│ └── collection.json // 为每个schematic定义元数据
├── README.md
├── package.json
└── tsconfig.json
</code></pre>
<h4 id="schematics的一些基本概念">Schematics的一些基本概念</h4>
<p>原理图的公共 API 定义了表达其基本概念的类。</p>
<ul>
<li>
<p>虚拟文件系统用 Tree(树)表示。Tree 数据结构包含一个基础状态 base(一组已经存在的文件)和一个 暂存区 staging(需要应用到 base 的更改列表)。在进行修改的过程中,你并没有真正改变它的 base,而是把那些修改添加到了暂存区。</p>
</li>
<li>
<p>Rule(规则)对象定义了一个函数,它接受 Tree,进行转换,并返回一个新的 Tree。原理图的主文件 index.ts 定义了一组实现原理图逻辑的规则。</p>
</li>
<li>
<p>转换由 Action(动作)表示。有四种动作类型:Create、Rename、Overwrite 和 Delete。</p>
</li>
<li>
<p>每个原理图都在一个上下文中运行,上下文由一个 SchematicContext 对象表示。</p>
</li>
</ul>
<p>传给规则的上下文对象可以访问该原理图可能会用到的工具函数和元数据,包括一个帮助调试的日志 API。上下文还定义了一个合并策略,用于确定如何将这些更改从暂存树合并到基础树中。可以接受或忽略某个更改,也可以抛出异常。</p>
<h2 id="简单上手">简单上手</h2>
<h4 id="创建一个blank的空模板">创建一个<code>blank</code>的空模板</h4>
<pre><code>$ schematics blank --name my-schematics
</code></pre>
<h4 id="成功之后看见如下目录结构">成功之后看见如下目录结构</h4>
<pre><code>├── node_modules/ // 依赖包
├── src
│ ├── my-schematics // 单个schematic文件夹
│ │ ├── index_spec.ts
│ │ ├── index.ts //定义命名原理图中转换逻辑的代码。
│ └── collection.json //为每个schematic定义元数据
├── README.md
├── package.json
└── tsconfig.json
</code></pre>
<h4 id="打开indexts并使用create创建文件">打开<code>index.ts</code>并使用<code>create</code>创建文件</h4>
<pre><code>import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function mySchematics(_options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
// (method) Tree.create(path: string, content: string | Buffer): void
tree.create("hello.ts","hello_world text")
return tree;
};
}
</code></pre>
<h4 id="执行以下指令">执行以下指令</h4>
<pre><code>$ npm run build // 打包你的schematics
$ npm link // 将你的schematics链接到全局
</code></pre>
<h4 id="然后使用angular-cli创建一个项目并用编辑器打开">然后使用<code>angular cli</code>创建一个项目,并用编辑器打开</h4>
<pre><code>$ ng new project
$ cd project
$ code .
</code></pre>
<h4 id="在angular项目中链接到你的schematics">在<code>angular</code>项目中链接到你的schematics</h4>
<pre><code>$ npm link my-schematics
</code></pre>
<p>注意:你的schematics名在你创建的schematics文件的package.json中</p>
<p><img src="https://img2020.cnblogs.com/blog/2196055/202011/2196055-20201104100035517-597518403.png" alt="image" loading="lazy"></p>
<h4 id="使用ng-g执行你的第一个schematics">使用<code>ng g</code>执行你的第一个schematics</h4>
<pre><code>$ ng g my-schematics:my-schematics
</code></pre>
<h4 id="或使用schematics执行你的第一个schematics">或使用<code>schematics</code>执行你的第一个schematics</h4>
<pre><code>$ schematics my-schematics:my-schematics
</code></pre>
<h4 id="如下代表成功">如下代表成功</h4>
<p><img src="https://img2020.cnblogs.com/blog/2196055/202011/2196055-20201104100155983-982875876.png" alt="" loading="lazy"></p>
<h4 id="知识点">知识点:</h4>
<pre><code>$ npm link $PATH_TO_SCHEMATIC_PROJECT
$ ng generate my-component:my-component someName
</code></pre>
<h4 id="补充">补充:</h4>
<p>为了方便,不用每次修改都运行 build,在此项目的 package.json 的 script 加入一行:</p>
<pre><code>"build:watch": "tsc -p tsconfig.json --watch"
</code></pre>
<p>使得该项目一致在 watch 状态下,然后运行</p>
<pre><code>npm run build:watch
</code></pre>
<h2 id="集合collection">集合(collection)</h2>
<p>在 Angular 中,集合(collection)是指收录在同一个 npm 包 中的一组原理图(schematics)。</p>
<h4 id="打开collectionjson并修改">打开collection.json,并修改</h4>
<pre><code>{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"my-schematics": {
"aliases": ["mfs"],
"description": "A blank schematic.",
"factory": "./my-schematics/index#mySchematics",
"schema": "./my-schematics/schema.json",
}
"my-extend-schematic": {
"description": "A schematic that extends another schematic.",
"extends": "my-schematics"
}
}
}
</code></pre>
<h4 id="api">APi</h4>
<table>
<thead>
<tr>
<th style="text-align: center">属性</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">$schema</td>
<td>定义该 collection 架构的 url 地址</td>
</tr>
<tr>
<td style="text-align: center">schematics</td>
<td>它描述了此系列中包含的原理图</td>
</tr>
<tr>
<td style="text-align: center">my-schematics</td>
<td>简单的描述一个工厂的字段</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th style="text-align: center">原理图可选参数</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><div style="width: 100px"> description </div></td>
<td>描述</td>
</tr>
<tr>
<td style="text-align: center">factory</td>
<td>用字符串引用来指向代表RuleFactory的JavaScript函数</td>
</tr>
<tr>
<td style="text-align: center">schema</td>
<td>用字符串引用来指向定义变量的schema.json</td>
</tr>
<tr>
<td style="text-align: center">extends</td>
<td>继承</td>
</tr>
<tr>
<td style="text-align: center">aliases</td>
<td>属性是一个数组,我们能用来指定我们的schematic的一个或者多个别名。举个例子,在Angular CLI中"generate" schematic的别名是"g"。这允许我们通过$ ng g调用generate命令</td>
</tr>
</tbody>
</table>
<h2 id="交互schema">交互(schema)</h2>
<h4 id="打开schemajson并修改">打开schema.json,并修改</h4>
<pre><code>{
"$schema": "http://json-schema.org/schema",
"id": "MyFullSchematicsSchema",
"title": "My Full Schematics Schema",
"type": "object",
"properties": {
"index": {
"type": "number",
"$default": {
"$source": "argv",
"index": 0
},
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
</code></pre>
<table>
<thead>
<tr>
<th style="text-align: center">属性说明</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">id</td>
<td>这个模式定义在集合中的唯一 id。</td>
</tr>
<tr>
<td style="text-align: center">title</td>
<td>一个人类可读的模式描述。</td>
</tr>
<tr>
<td style="text-align: center">type</td>
<td>由这些属性提供的类型描述符。</td>
</tr>
<tr>
<td style="text-align: center">properties</td>
<td>一个定义该原理图可用选项的对象。</td>
</tr>
<tr>
<td style="text-align: center">required</td>
<td>必填的选项</td>
</tr>
</tbody>
</table>
<h4 id="properties-中定义变量的可选参数api"><code>properties</code> 中定义变量的可选参数API</h4>
<table>
<thead>
<tr>
<th style="text-align: center">可选参数</th>
<th>描述</th>
<th>类型</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">type</td>
<td>传入类型</td>
<td></td>
</tr>
<tr>
<td style="text-align: center">default</td>
<td>默认参数</td>
<td></td>
</tr>
<tr>
<td style="text-align: center">$default</td>
<td>如果没有指定输入的选项,则自行指定</td>
<td></td>
</tr>
<tr>
<td style="text-align: center">description</td>
<td>描述</td>
<td>string</td>
</tr>
<tr>
<td style="text-align: center">minLength</td>
<td>最小长度</td>
<td>number</td>
</tr>
<tr>
<td style="text-align: center">maxLength</td>
<td>最大长度</td>
<td>number</td>
</tr>
<tr>
<td style="text-align: center">x-prompt</td>
<td>添加一个提示</td>
<td></td>
</tr>
<tr>
<td style="text-align: center">enum</td>
<td>枚举成员成为列表中的选择项</td>
<td></td>
</tr>
</tbody>
</table>
<p><code>$default</code></p>
<table>
<thead>
<tr>
<th style="text-align: center">属性</th>
<th>描述</th>
<th>类型</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">$source</td>
<td>可指定 "argv" 参数</td>
<td></td>
</tr>
<tr>
<td style="text-align: center">index</td>
<td>选择获取参数的下标</td>
<td>number</td>
</tr>
</tbody>
</table>
<p><code>x-prompt</code><br>
|属性| 描述|<br>
|:----:| ----| ----|<br>
|type| confirmation,input 或 list (以简短形式自动选择)|<br>
|message| 字符串(必填) |number |<br>
|items| 字符串和/或“标签/值”对象(仅对 list 类型有效) |</p>
<h4 id="例">例:</h4>
<pre><code>"style": {
"description": "The file extension or preprocessor to use for style files.",
"type": "string",
"default": "css",
"enum": [
"css",
"scss",
"sass",
"less",
"styl"
],
"x-prompt": {
"message": "Which stylesheet format would you like to use?",
"type": "list",
"items": [
{ "value": "css","label": "CSS" },
{ "value": "scss", "label": "SCSS [ https://sass-lang.com/documentation/syntax#scss ]" },
{ "value": "sass", "label": "Sass [ https://sass-lang.com/documentation/syntax#the-indented-syntax ]" },
{ "value": "less", "label": "Less [ http://lesscss.org ]" },
{ "value": "styl", "label": "Stylus [ http://stylus-lang.com ]" }
]
},
},
</code></pre>
<p>参考 x-prompt schema</p>
<h2 id="使用文件模板">使用文件模板</h2>
<p>新建一个<code>"blank"</code>的<code>schematics</code>然后</p>
<h4 id="打开indexts-入口文件并修改">打开<code>index.ts</code> 入口文件,并修改</h4>
<pre><code>import {
Rule,
apply,
mergeWith,
template,
url,
} from '@angular-devkit/schematics';
import { strings } from '@angular-devkit/core';
// You don't have to export the function as default. You can also have more than one rule factory
// per file.
export function mySchematics(options: any): Rule {
returnmergeWith(apply(url('./files'), [
template({
...options, // 拿到schema.json 中定义的变量
...strings, // 添加模板方法
}),
move('src/')
]))
}
</code></pre>
<h4 id="添加schemajson与files文件夹">添加schema.json与files文件夹</h4>
<p>schema.json 修改如下</p>
<pre><code>{
"$schema": "http://json-schema.org/schema",
"id": "MyFullSchematicsSchema",
"title": "My Full Schematics Schema",
"type": "object",
"properties": {
"index": {
"type": "number",
"default": 1
},
"name": {
"type": "string"
}
},
"required": [
"name"
]
}
</code></pre>
<p>files 文件修改如下 :<br>
新建<code>test__name@classify__</code> 文件,并填入以下内容</p>
<pre><code>
<% if (name) { %>
Hello <%= dasherize(name) %>, I'm a schematic.
<% } else { %>
Why don't you give me your name with --name?
<% } %>
</code></pre>
<p><img src="https://img2020.cnblogs.com/blog/2196055/202011/2196055-20201104100309553-2121105420.png" alt="" loading="lazy"></p>
<h4 id="执行代码看看效果吧">执行代码看看效果吧!</h4>
<h4 id="知识点-1">知识点</h4>
<table>
<thead>
<tr>
<th style="text-align: center">属性</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><div style="width: 100px"> mergeWith()</div></td>
<td>则合并两个tree;一个来自source(没有base的tree),另一个作为rule的输入。您可以将其视为在当前更改的基础上重新设置source。</td>
</tr>
<tr>
<td style="text-align: center">apply()</td>
<td>获取source,并对其应用rule</td>
</tr>
<tr>
<td style="text-align: center">url()</td>
<td>它接受一个url并返回一个包含该url中所有文件的tree</td>
</tr>
<tr>
<td style="text-align: center">template()</td>
<td>该rule获取一个tree并对其应用两个模板:路径模板:此模板用值替换路径中的\uux\uuu实例从传递给template()的选项中选择X。如果X的值是a函数,则将调用该函数。如果X未定义或返回null(不是空字符串),文件或路径将被删除。</td>
</tr>
<tr>
<td style="text-align: center">move()</td>
<td>接收传入的路径字符串作为rule 返回给template(),用来指定文件生成路径</td>
</tr>
</tbody>
</table>
<h4 id="模板文件">模板文件</h4>
<p>简单说明两个函数</p>
<h4 id="引用模板方法后使用">引用模板方法后使用:</h4>
<pre><code> import { strings } from '@angular-devkit/core';
template({
...strings,
}),
</code></pre>
<table>
<thead>
<tr>
<th style="text-align: center">属性</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><div style="width: 100px"> classify()</div></td>
<td>该方法接受一个值,并返回标题格式(title case)的值。比如,如果提供的名字是 my service,它就会返回 MyService。</td>
</tr>
<tr>
<td style="text-align: center"><div> dasherize() </div></td>
<td>该方法接受一个值,并以中线分隔并小写的形式返回值。比如,如果提供的名字是 MyService,它就会返回 “my-service” 的形式。</td>
</tr>
</tbody>
</table>
<h4 id="路径模板">路径模板</h4>
<pre><code>variable@function
</code></pre>
<p>使用<code>__variable__</code> 定义变量,使用<code>@</code>调用方法,例如:<br>
<img src="https://img2020.cnblogs.com/blog/2196055/202011/2196055-20201104100355723-2138218605.png" alt="" loading="lazy"></p>
<h4 id="内容模板">内容模板</h4>
<p>使用EJS模板语法,无需安装直接使用</p>
<pre><code><% if (name) { %>
Hello <%= dasherize(name) %>, I'm a schematic.
<% } else { %>
Why don't you give me your name with --name?
<% } %>
</code></pre>
<p>参考EJS官方文档</p>
<h2 id="补充-1">补充</h2>
<h4 id="可以利用-schematicsangular-包提供的实用工具寻求辅助函数来处理模块依赖typescriptastjsonangular-cli-工作空间和项目等等">可以利用 <code>@schematics/angular</code> 包提供的实用工具。寻求辅助函数来处理模块、依赖、TypeScript、AST、JSON、Angular CLI 工作空间和项目等等</h4>
<pre><code>npm i @schematics/angular
</code></pre>
<pre><code>import {
JsonAstObject,
JsonObject,
JsonValue,
Path,
normalize,
parseJsonAst,
strings,
} from '@angular-devkit/core';
</code></pre>
<p>到这里入门部分就讲解完成了!!!</p>
<h2 id="下集预告">下集预告</h2>
<h4 id="如何在库中使用schematics">如何在库中使用schematics</h4><br><br>
来源:https://www.cnblogs.com/Yasg/p/13902454.html
頁:
[1]