浅谈Angular Cli Schematics

作者: cipchk | 来源:发表于2018-07-31 21:36 被阅读13次

    写在前面

    Schematics 是前端开发工作流工具,例如:创建一个组件、变更配置项至当前项目。并且不限制任何语言环境;虽然如此,但 Schematics 目前依然只能依赖 Angular Cli 来运行相应的命令行。

    本文是在重构 ng-alain schematics 时阅读 @angular-devkit 源码的一些记录;而关于 Schematics 的运用在知乎上有好几篇不错的文章,我将尽可能跳开一些不必要的重复性工作,建议阅读本文时可以同下列文章一起阅读。

    指令类型

    Schematics 一共包含四个指令:

    • add 添加一个 Library 至项目
    • new 创建一个新 Angular 项目
    • generate 基于 Schematics 创建或修改文件
    • update 更新应用程序或依赖项

    其实除了 add 会事先执行一次 npm i (取决于 angular.jsoncli/packageManager 配置值,默认:npm)指令以外,其他指令实际上都是基于 Schematics 创建或修改文件。

    generate 指令会更纯粹,需要你手动指定 Schematic 名称,例如:ng g class <ClassName>。其他三个指令是对其进一步简化,像 ng add 实际相当于 ng g ng-add 这里的 ng-add 是固定名称,若你希望创建一个支持 ng add 那么你就必须有一个 ng-add 的 Schematic。

    执行原理

    Schematics 执行核心的本质就是在维护一个非常大的 Observable 数据流,这里的数据就是文件树。

    核心的主轴是执行一个 Schematics 时会在开始时构建一个虚拟文件系统 virtual-fs 就像 Rxjs 的 Observable,后续的操作符都是对文件系统的变更动作,最后将虚拟文件系统的内容影射至物理文件中。

    一个 Schematics 可以包含多个不同的指令,例如默认 Angular Schematics 有非常多我们熟悉的 modulecomponent 等,而管理这些指令是通过 collection.json 配置项。

    Schematics 创建完虚拟文件系统环境后,紧跟着依 collection.json 构建 Collection 对象,再根据指令中的名称创建 Schematic 对象;并且调用并运行 Schematic Name 所对应目录名下 index.ts 文件,例如一个 Schematic 完整的代码结构:

    function rule1() {
      return (host: Tree, context: SchematicContext) => {
          // doing
      };
    }
    export default function(options: ApplicationOptions): Rule {
      return (host: Tree, context: SchematicContext) => {
        return chain([ rule1(), rule1() ]);
      }
    }
    

    最终返回一个 Rule 类型,其本质是:

    (tree: Tree, context: SchematicContext) => Tree | Observable<Tree> | Rule | void
    

    若返回的是一个 Observable 类型时意味者这里的空间变得无限大:

    function rule1() {
      return (host: Tree, context: SchematicContext) => {
          return of(host);
      };
    }
    

    比如构建自己的远程代码片断库。

    任务器

    Schematics 除了运行 Schematic 指令以外,还需要一些对项目进行额外操作,例如:安装Node依赖包、初始化 Git 等。其实运行 Schematic 指令本身也是一种任务。这些任务是通过 SchematicContext 进行管理。

    例如我们希望在执行一个 Schematic 指令后调用一次 Node 依赖包的安装,只需要调用内置的 NodePackageInstallTask 任务:

    (host: Tree, context: SchematicContext) => {
        context.addTask(new NodePackageInstallTask());
    }
    

    Angular.json

    angular.json 与 Schematic 有着非常密切的关系,大多数需要通过 angular.json 配置信息来获取目录路径、默认配置项等信息。特别是当编写 Schematic 时总是需要考虑多项目的情况,因此绝大多数都需要依赖 angular.json 来确认具体项目名及路径信息。

    每一个 Schematic 指令都有相应的参数信息,这些参数信息也可以直接被映射在 angular.json 上面并当成默认参数值:

    {
      "schematics": {
        "ng-alain:list": {
          "spec": false
        },
        "@schematics/angular:component": {
          "spec": false
        }
      }
    }
    

    通过 ng g ng-alain:module <name>(或 ng g component <name>)生成时将忽略测试文件;当然对于这些默认参数的转化都是 Schematics 内自动完成。

    总结

    以上是一些简单总结,Schematics 可玩性非常强,它是运行在一个 Node 容器内,因此可以使用当下所有 Node 类库。

    而 Schematics 的操作除了文件以外,也会对文件内容进行修改,这一些也很有意思。像 ts 文件可以利用 typescript 类库来获取或调整 ts 文件内容某个变量名或值。而 html 文件可以利用 parse5 来解析并修改,绝大多数文件类型都可以找到相对应的现有类库来支持。

    Schematics 只是 @angular-devkit 中的一小部分而已,还包括:Architect 用于改变 Angular cli 的运行机制,虽然本质上是在改变 Webpack 配置文件,但谁叫 Webpack 有着无限可能呢。

    原先 @angular-devkit 是作为一个独立的仓储位于 @angular/devkit,然而不久前被合并入 @angular-cli 里。

    (完)

    相关文章

      网友评论

        本文标题:浅谈Angular Cli Schematics

        本文链接:https://www.haomeiwen.com/subject/dsdkvftx.html