
Schematics 是现代网络的工作流程工具;它可以将转换应用于您的项目,例如创建新组件,或更新代码以修复依赖项中的重大更改。或者您可能想向现有项目添加新的配置选项或框架。
Angular CLI 的使命是提高您的开发效率。我们需要一个更强大、更通用的工具来支持 CLI 脚手架,我们确定了 4 个主要目标:
在示意图中,您实际上并不对文件系统执行任何直接操作。相反,您描述您想要对Tree
应用什么转换。这使我们能够支持诸如试运行(或补丁运行)之类的功能,而无需从原理图本身添加特殊支持。它还使原理图密封,确保可重用性和安全性。
这Tree
是一种数据结构,包含基础(一组已存在的文件)和暂存区域(要应用于基础的更改列表)。进行修改时,您实际上并没有更改基础,而是将这些修改添加到暂存区域。这确实很强大,但可能很棘手,将在单独的媒体帖子中进一步探讨。
原理图将接收的Tree
可以是任何东西。 Angular CLI 将使用Tree
来表示驱动器上的项目到它调用的第一个原理图,但组合原理图可以接收任何Tree
。好消息是,这并不重要。 Tree
代表您的起点。
首先,确保您安装了 Node 6.9 或更高版本。接下来,全局安装 Schematics 命令行工具:
npm install -g @angular-devkit/schematics-cli
这将安装一个schematics
可执行文件,您可以使用它来创建一个空白的原理图项目:
schematics blank --name=my-component
等等瞧。 blank
原理图可以创建一个新项目,也可以将空白原理图添加到现有项目中(两者都可以使用)。然后,您可以cd
进入新项目,安装 npm 依赖项,并使用您最喜欢的编辑器打开新集合:
cd my-component
npm install
code . # or atom, webstorm, vi, ...
原理图集合是一组命名原理图,由用户发布和安装。例如,Angular 团队发布并维护官方@schematics/angular
集合,其中包含component
、 module
和application
等原理图。
在我们的例子中,我们的集合将仅包括my-component
原理图。你可以查看src/collection.json
文件,其中包含我们集合的描述:
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"my-component": {
"description": "A blank schematic.",
"factory": "./my-component/index#myComponent"
}
}
}
$schema
键指向定义此格式的 JSON 架构。它被 IDE 用于自动完成、验证工具,并且完全是可选的。
重要的关键是"schematics"
,它描述了该集合中包含的原理图。在我们的示例中,我们描述了一个原理图: my-component
,它有一个简单的描述和一个工厂字段。 factory
字段使用字符串引用来指向 JavaScript 函数;在我们的例子中,导出函数myComponent
在文件my-component/index.js
中。它代表RuleFactory
。
Rule
是一个函数,它接受一个Tree
并返回另一个Tree
。规则是Schematics的核心;他们是对您的项目进行更改、调用外部工具和实现逻辑的人。 RuleFactory
,顾名思义,是创建Rule
的函数。
这是迄今为止创建的空白RuleFactory
:
// index.ts
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 myComponent(options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
return tree;
};
}
该工厂接受一个options
参数并返回一个Rule
,该规则接受一个Tree
并返回它不变。
options
参数是一个可以视为工厂输入的对象。在 CLI 中,它是用户传递的命令行参数。从另一个原理图来看,它是该原理图传入的选项。例如,GUI 工具可以根据用户或项目输入构建选项对象。
无论如何,这始终是一个对象,并且可以键入为any
。还可以使用 JSON 架构对其进行验证,以确保输入具有适当的默认值和类型。 JSON 模式将在后面的文章中更仔细地讨论。
与此同时,让我们用我们的规则做一些更有趣的事情:
// index.ts
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 myComponent(options: any): Rule {
return (tree: Tree, _context: SchematicContext) => {
tree.create(options.name || 'hello', 'world');
return tree;
};
}
通过这一新行,我们在原理图的Tree
的根目录中创建一个文件,以name
选项(默认情况下为'hello'
)命名,包含字符串world
。目前看来这似乎微不足道,但背后却发生了很多事情。
Tree
包含应应用原理图的文件。它有一个文件列表,并包含与您要应用的更改相关的元数据。在我们的例子中,所做的唯一更改是创建一个新文件。树比仅仅作为文件系统等价物更复杂,并将在后面的文章中更深入地探讨,但目前您可以将它们视为文件和更改的集合。
默认情况下,Angular CLI 会将 Angular 项目的根作为Tree
传递,但任何原理图都可以将不同的Tree
传递给其他原理图。您可以创建空树、将Tree
范围限定为父Tree
的目录、合并两棵树或对它们进行分支(制作其副本)。
有四种方法可以直接在Tree
中创建更改; create
、 delete
、 rename
和overwrite
。
要运行我们的示例,您首先需要构建它,然后使用schematics
命令行工具,并将原理图项目目录的路径作为集合。从我们项目的根源来看:
npm run build
# ... wait for build to finish
schematics .:my-component --name=test
# ... see that a file is created in the root.
在进一步研究这里发生的事情之前,先警告一下;别担心,这次您实际上并没有在文件系统上创建文件。这是因为当使用路径作为它应该使用的集合时, schematics
工具处于调试模式。在调试时(也可以与--debug=true
一起使用),默认情况下也是在试运行模式下运行,这会阻止该工具实际创建文件。
这可以使用参数--dry-run=false
进行更改。但请注意,这意味着更改将真正发生在文件系统上。如果删除或覆盖文件,您可能会丢失您不想要的内容。我们建议在调试原理图时位于单独的临时目录中,并仅在必要时禁用试运行。
您还可以在单独的终端中启动npm run build -- -w
以便在文件更改时自动重建原理图项目。
为了调试原理图,您需要在调试模式下运行节点:
node --inspect-brk $(which schematics) .:myComponent --name=test
在调试模式下运行的另一个优点是schematics
命令行工具在运行您自己的原理图之前直接放置一个断点。
Schematics 的一大优势在于它们很容易组合在一起。在我们的示例中,我们将从 Angular 集合中调用component
原理图,以将组件添加到您的应用程序中,然后向原理图添加的每个 TypeScript 文件添加标头。
// index.ts
import { Rule, SchematicContext, Tree, chain, externalSchematic } from '@angular-devkit/schematics';
const licenseText = `
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
`;
export function myComponent(options: any): Rule {
return chain([
externalSchematic('@schematics/angular', 'component', options),
(tree: Tree, _context: SchematicContext) => {
tree.getDir(options.sourceDir)
.visit(filePath => {
if (!filePath.endsWith('.ts')) {
return;
}
const content = tree.read(filePath);
if (!content) {
return;
}
// Prevent from writing license to files that already have one.
if (content.indexOf(licenseText) == -1) {
tree.overwrite(filePath, licenseText + content);
}
});
return tree;
},
]);
}
不要忘记将@schematics/angular
添加到package.json
中的依赖项中!
这里有几点需要注意。首先,我们直接调用并返回chain()
。 chain()
是 Schematics 库提供的一个RuleFactory
,它将多个规则链接在一起,并在规则之间等待Rule
完成。 Schematic 库还提供了其他类似的规则工厂,我们稍后会详细介绍它们。
其次,我们使用另一个名为externalSchematic
的RuleFactory
(它还有一个名为schematic
的姊妹工厂)。原理图是规则,您可能会想简单地导入原理图的规则工厂并自己创建规则,然后直接调用它(或直接将其传递到链)。不要直接将其他 Schematics 称为Rule
。 externalSchematic
(和schematic
)规则工厂比导入原理图并运行它有更多的逻辑。例如,验证架构并填充默认值。
最后,目前没有好的方法来列出在树中创建或覆盖的文件。由于 Schematics 的构建是封闭的,因此您收到的Tree
没有局部更改。因此,我们必须检查所有文件。
目前,用户使用 Schematics 的最佳方式是通过 Angular CLI。这意味着您应该在将其发布到 NPM 之前尝试一下。在这里,我们将尝试通过 Angular CLI 使用新的myComponent
原理图。
首先,使用 CLI 创建一个空项目:
ng new my-project
然后在您的新项目中,链接我们刚刚构建的原理图:
npm link $PATH_TO_SCHEMATIC_PROJECT
将$PATH_TO_SCHEMATIC_PROJECT
替换为项目根目录的路径。请注意,用户将安装而不是链接,这只是为了在开发时在本地更快地迭代。
链接原理图项目后,您可以使用ng generate
来调用原理图:
ng generate my-component:my-component someName
默认情况下,如果原理图采用name
参数,则生成命令的第二个参数将设置为该名称。
瞧!这应该足以让您的用户开始使用。请注意,您还可以在 CLI 配置中设置一个默认集合。有关配置的更多信息,请参阅 CLI wiki。
回顾一下到目前为止我们学到的东西:
chain
和externalSchematic
规则工厂来编写规则并调用其他原理图。在下一篇博客文章中,我将更深入地访问Tree
数据结构,并查看任务,任务可用于以智能且安全的方式调用外部进程。
Schematics 是 Angular DevKit 更大努力的第一部分,未来将包含许多其他库,这些工作将在单独的帖子中描述。
欢呼,干杯!
文章来源地址:https://blog.angular.dev/schematics-an-introduction-dc1dfbc2a2b2