-->
关于 Angular 原理图的介绍和如何使用可以直接看官方文档:https://angular.cn/guide/schematics
本文是 GitHub 仓储 angular_devkit/schematics 的中文翻译。
现代 Web 的一个脚手架库。
原理图是转换现有文件系统的生成器。它可以创建文件、重构现有文件或移动文件。
原理图与其他生成器(如 Yeoman 或 Yarn Create)的区别在于,原理图纯粹是描述性的;原理图是没有副作用的,在所有内容都提交之前,不会对实际的文件系统应用任何更改。根据设计,原理图中没有副作用。
术语 | 描述 |
---|---|
Schematics | 在现有文件系统上执行描述性代码而不产生副作用的生成器。 |
Collection | 原理图元数据列表。原理图可以在集合中按名称引用。 |
Tool | 使用原理图库的代码。 |
Tree | 用于更改的暂存区域,包含原始文件系统和要应用于该系统的更改列表。 |
Rule | 将 Action 应用于Tree 的函数。它返回一个新的Tree ,其中包含所有转换。 |
Source | 从空文件系统创建一个全新的Tree 的函数。例如: 文件源可以从磁盘读取文件,并为每个文件创建 Create Action。 |
Action | 需要验证并提交到文件系统或Tree 的原子操作。Action 由原理图创建。 |
Sink | 所有Action 的最终结果。 |
原理图是一个类库,它本身不执行,reference CLI 在这个仓储中可用,并且发布到 NPM @angular-devkit/schematics-cli。此档解释了库的用法和工具 API,但不涉及工具实现本身。
工具负责以下任务:
FileSystemSink
和DryRunSink
。工具 API 由以下部分组成:
SchematicEngine
负责加载和构造Collection
和Schematics
。在创建引擎时,该工具提供一个EngineHost
接口,EngineHost
表示如何通过一个集合名称创建CollectionDescription
,以及如何创建SchematicDescription
原理图是生成器,并且是 Collection
的一部分。
集合通过一个collection.json
文件定义的(在 reference CLI 中)。JSON 定义有如下属性:
属性名 | 类型 | 描述 |
---|---|---|
name | string | 集合的名称. |
version | string | 无用的字段,表示版本. |
Source
是一个Tree
的生成器;它创建一个新的入口 Root Tree,Rule
是从Tree
到另一颗Tree
的转换。Schematic
(在根目录下)是通常应用于文件系统的Rule
。
FileOperator
将更改单个FileEntry
并返回新的FileEntry
, 结果遵循以下规则:
FileEntry
为空,则DeleteAction
将添加到操作列表中。RenameAction
将添加到 Action 列表中。OverwriteAction
。使用FileOperator
创建文件是不可能的。
原理图库默认提供了多个涵盖基本场景的Operator
工厂:
FileOperator | Description |
---|---|
contentTemplate<T>(options: T) | 应用内容模板(请参见模板章节) |
pathTemplate<T>(options: T) | 应用路径模板 (请参见模板章节) |
原理图库默认还提供多个Source
工厂:
Source | Description |
---|---|
empty() | 创建一个源并返回一个空 Tree 。 |
source(tree: Tree) | 创建一个源并返回一个通过参数传的Tree 。 |
url(url: string) | 从给定的 URL 加载文件列表,并返回一个文件Tree ,这些Tree 通过CreateAction 应用于一个空的Tree 。 |
apply(source: Source, rules: Rule[]) | 对一个Source 进行一系列 Rule 操作,返回一个新的Source 。 |
原理图库默认还提供多个Rule
工厂:
Rule | Description |
---|---|
noop() | 按原样返回输入的 Tree 。 |
chain(rules: Rule[]) | 返回一个串联多个Rule 的一个新 Rule 。 |
forEach(op: FileOperator) | 将运算符应用于输入Tree 的每个文件,并返回Rule 。 |
move(root: string) | 将所有文件从输入移动到子目录。 |
merge(other: Tree) | 将输入的Tree 合并到另一个Tree 。 |
contentTemplate<T>(options: T) | 将内容模板(请参阅模板部分)应用于整个Tree 。 |
pathTemplate<T>(options: T) | 将路径模板(请参见模板部分)应用于整个Tree 。 |
template<T>(options: T) | 将路径模板和内容模板(请参见模板部分)应用于整个Tree 。 |
filter(predicate: FilePredicate<boolean>) | 返回输入Tree ,其中包含不传递FilePredicate 的文件。 |
As referenced above, some functions are based upon a file templating system, which consists of path and content templating.
The system operates on placeholders defined inside files or their paths as loaded in the Tree
and fills these in as defined in the following, using values passed into the Rule
which applies the templating (i.e. template<T>(options: T)
).
Placeholder | Description |
---|---|
variable | Replaced with the value of variable . |
variable@function | Replaced with the result of the call function(variable) . Can be chained to the left (__variable@function1@function2__ etc). |
Placeholder | Description |
---|---|
<%= expression %> | Replaced with the result of the call of the given expression. This only supports direct expressions, no structural (for/if/…) JavaScript. |
<%- expression %> | Same as above, but the value of the result will be escaped for HTML when inserted (i.e. replacing ’<’ with ’<’) |
<% inline code %> | Inserts the given code into the template structure, allowing to insert structural JavaScript. |
<%# text %> | A comment, which gets entirely dropped. |
An example of a simple Schematics which creates a “hello world” file, using an option to determine its path:
import { Tree } from '@angular-devkit/schematics';
export default function MySchematic(options: any) {
return (tree: Tree) => {
tree.create(options.path + '/hi', 'Hello world!');
return tree;
};
}
A few things from this example:
Rule
, which is a transformation from a Tree
to another Tree
.A simplified example of a Schematics which creates a file containing a new Class, using an option to determine its name:
// files/__name@dasherize__.ts
export class <%= classify(name) %> {
}
// index.ts
import { strings } from '@angular-devkit/core';
import {
Rule,
SchematicContext,
SchematicsException,
Tree,
apply,
branchAndMerge,
mergeWith,
template,
url
} from '@angular-devkit/schematics';
import { Schema as ClassOptions } from './schema';
export default function (options: ClassOptions): Rule {
return (tree: Tree, context: SchematicContext) => {
if (!options.name) {
throw new SchematicsException('Option (name) is required.');
}
const templateSource = apply(url('./files'), [
template({
...strings,
...options
})
]);
return branchAndMerge(mergeWith(templateSource));
};
}
Additional things from this example:
strings
provides the used dasherize
and classify
functions, among others.index.ts
and loaded into a Tree
.template
Rule
fills in the specified templating placeholders. For this, it only knows about the variables and functions passed to it via the options-object.Tree
, containing the new file, is merged with the existing files of the project which the Schematic is run on.Schematics is not done yet. Here’s a list of things we are considering: