当前位置: 首页 > Web前端 > JavaScript

AngularSchematicsSchematicsLearning-Hands-OnDevelopmentAPracticalExample

时间:2023-03-27 17:28:07 JavaScript

当ngadd命令向项目添加库时运行Schematics。nggenerate命令运行原理图来创建应用程序、库和Angular代码块。一些术语:Rule在Schematic中,指的是对文件树进行操作,以指定的方式创建、删除或修改文件,并返回一个新的Tree对象的函数。文件树在示意图中,是一个用Tree类表示的虚拟文件系统。示意图规则将树对象作为输入,对其进行操作,并返回一个新的树对象。开发人员可以创建以下三个原理图:安装原理图以便ngadd可以将您的库添加到项目中。生成原理图,以便nggenerate可以在项目中提供定义的工件(组件、服务、测试等)。更新原理图ngupdate可以更新你的库的依赖项,并提供一些迁移来破坏新版本中的更改。下面我们来做一个例子。在库的根文件夹中,创建一个schematics/文件夹。在schematics/文件夹中,为您的第一个原理图创建一个ng-add/文件夹。在schematics/文件夹的根目录下,创建一个collection.json文件。编辑collection.json文件以定义集合的初始架构定义。如下图所示:collection.json文件内容如下:{"$schema":"../../../node_modules/@angular-devkit/schematics/collection-schema.json","schematics":{"ng-add":{"description":"将我的库添加到项目中。","factory":"./ng-add/index#ngAdd"},"my-service":{"description":"在项目中生成一个服务。","factory":"./my-service/index#myService","schema":"./my-service/schema.json"}}}下图中高亮的那一行表示:当执行ngadd时,会调用ng-add文件夹下的index.ts文件。也就是这个文件:我们需要在my-lib库根目录的package.json中声明对上面collection.json文件的引用:ngadd命令的示意图可以增强用户的初始安装过程。这样的示意图可以定义如下。(1)进入/schematics/ng-add/目录。(2)创建主文件index.ts。(3)打开index.ts,添加原理图工厂函数源码:import{Rule,SchematicContext,Tree}from'@angular-devkit/schematics';import{NodePackageInstallTask??}from'@angular-devkit/schematics/tasks';//只返回树导出函数ngAdd(options:any):Rule{return(tree:Tree,context:SchematicContext)=>{context.addTask(newNodePackageInstallTask??());返回树;};}提供初始ngadd支持所需的唯一步骤是使用SchematicContext触发安装任务。此任务将使用用户首选的包管理器将库添加到宿主项目的package.json配置文件中,并将其安装在项目的node_modules目录中。在此示例中,该函数采用当前Tree并在不进行修改的情况下返回它。如果需要,您还可以在安装包时进行其他设置,例如制作文件、更新配置或库所需的任何其他初始设置。定义依赖类型如果库需要添加到dependencies,devDepedencies中,或者不保存到项目的package.json配置文件中,请使用ng-add的保存选项配置"ng-add":{"save":"devDependencies"}可能的值是:false-不要将这个包添加到package.jsontrue-将这个包添加到dependencies"dependencies"-添加这个包到dependencies"devDependencies"-添加这个包到devDependencies构建你的原理图必须首先构建库本身,然后构建原理图。你的库需要一个自定义的Typescript配置文件,其中包含一些关于如何将原理图编译到库的分发版中的说明。要将这些原理图添加到库的分发版中,请将这些脚本添加到库的package.json文件中。假设您的Angular工作区中有一个库项目my-lib。要告诉库如何构建原理图,请在生成的tsconfig.lib.json库配置文件旁边添加一个tsconfig.schematics.json文件。新建一个tsconfig.schematics.json文件,维护如下源码:{"compilerOptions":{"baseUrl":".","lib":["es2018","dom"],"declaration":true,“module”:“commonjs”,“moduleResolution”:“node”,“noEmitOnError”:true,“noFallthroughCasesInSwitch”:true,“noImplicitAny”:true,“noImplicitThis”:true,“noUnusedParameters”:true,“noUnusedLocals”:真,“rootDir”:“示意图”,“outDir”:“../../dist/my-lib/schematics”,“skipDefaultLibCheck”:真,“skipLibCheck”:真,“sourceMap”:真,“strictNullChecks":true,"target":"es6","types":["jasmine","node"]},"include":["schematics/**/*"],"exclude":["schematics/*/files/**/*"]}rootDir表示你的schematics/文件夹中包含要编译的输入文件,即下图中高亮显示的文件:outDir映射到库的输出目录。默认情况下,这是工作区根目录下的dist/my-lib文件夹,里面有以下文件:为保证你的原理图源文件编译成库包,请在库工程中添加如下脚本在根文件夹(projects/my-lib)下的package.json文件中。{“名称”:“我的库”,“版本”:“0.0.1”,“脚本”:{“构建”:“../../node_modules/.bin/tsc-ptsconfig.schematics.json","copy:schemas":"cp--parentsschematics/*/schema.json../../dist/my-lib/","copy:files":"cp--parents-pschematics/*/files/**../../dist/my-lib/","copy:collection":"cpschematics/collection.json../../dist/my-lib/schematics/collection.json","postbuild":"npmruncopy:schemas&&npmruncopy:files&&npmruncopy:collection"},"peerDependencies":{"@angular/common":"^7.2.0","@angular/core":"^7.2.0"},"schematics":"./schematics/collection.json","ng-add":{"save":"devDependencies"}}使用自定义tsconfig.schematics构建脚本。json文件来编译你的原理图。copy:*语句将编译后的原理图文件复制到库输出目录下的正确位置,同时保持目录结构。postbuild脚本在构建脚本完成后复制原理图文件。提供生成器支持您可以将命名原理图添加到集合中,允许您的用户使用nggenerate命令创建您在库中定义的工件。假设您的库定义了一个需要一些设置的服务my-service。您希望用户能够使用下面的CLI命令生成它。nggeneratemy-lib:my-service首先,在schematics文件夹中创建一个新的子文件夹my-service。编辑schematics/collection.json文件,指向新的原理图子文件夹,并附加一个指向模式文件指向将为新原理图指定输入的文件的指针。转到/schematics/my-service/目录。创建一个schema.json文件并定义示意图的可用选项。每个选项都将一个键与一个类型、描述和一个可选的别名相关联。该类型定义了您期望的值的形状,并在用户向您的原理图寻求使用帮助时显示此描述。创建一个schema.ts文件并定义一个接口,用于存储schema.json文件中定义的每个选项的值。exportinterfaceSchema{//服务的名称。名称:字符串;//创建服务的路径。路径?:字符串;//项目名称。项目?:字符串;此服务的指定名称。路径:覆盖为原理图提供的路径。默认情况下,路径基于当前工作目录。project:提供运行原理图的具体工程。在原理图中,如果用户没有给出选项,你可以提供一个默认值。要将工件添加到项目中,您的原理图需要有自己的模板文件。原理图模板支持特殊语法来执行代码和变量替换。在schematics/my-service/目录下创建一个files/文件夹。创建一个名为__name@dasherize__.service.ts...的文件,它定义了一个可用于生成文件的模板。此处的模板生成一个服务,该服务将Angular的HttpClient注入到其构造函数中。文件内容如下://#docregiontemplateimport{Injectable}from'@angular/core';import{HttpClient}from'@angular/common/http';@Injectable({providedIn:'root'})exportclass<%=classify(name)%>Service{constructor(privatehttp:HttpClient){}}classify和dasherize方法是您的原理图将用于转换模板源代码和文件名的实用函数。name是工厂函数提供的属性。它与您在架构中定义的名称相同。添加工厂函数现在您已经有了基础设施,您可以开始定义一个主要函数来执行您想要对您的用户项目进行的各种修改。Schematics框架提供了一个文件模板系统,支持路径和内容模板。系统操纵在这个输入树(Tree)或路径中加载的文件中定义的占位符,用传递给规则的值填充它们。有关这些数据结构和语法的详细信息,请参阅SchematicsREADME。创建主文件index.ts并添加原理图工厂功能的源代码。首先,导入你需要的原理图定义。Schematics框架提供了许多实用函数来创建规则或在执行原理图时使用规则。代码如下:import{Rule,Tree,SchematicsException,apply,url,applyTemplates,move,chain,mergeWith}from'@angular-devkit/schematics';从'@angular-devkit/core'导入{strings,normalize,virtualFs,workspaces};导入已定义的模式接口,重新定义为带有别名的MyServiceSchema,这将为您的原理图选项提供类型信息。要构建“生成器原理图”,我们从空白规则工厂开始。在index.js文件中:exportfunctionmyService(options:MyServiceSchema):Rule{return(tree:Tree)=>{returntree;};}这个规则工厂返回没有任何修改的树。这些选项是从nggenerate命令传递过来的选项值。定义构建器规则我们现在有了一个框架,用于创建一些实际修改用户程序的代码,以便设置库中定义的服务。用户安装此库的Angular工作区将包含多个项目(应用程序和库)。用户可以在命令行中指定一个项目,或者使用它的默认值。无论哪种情况,您的代码都需要知道该原理图应应用于哪个项目,以便它可以从该项目的配置中检索信息。您可以使用传递给工厂函数的Tree对象来执行此操作。通过Tree的一些方法,可以访问到这个工作区完整的文件树,这样运行原理图的时候就可以读写文件了。获取项目配置要确定目标项目,请使用workspaces.readWorkspace方法读取工作空间根目录下的工作空间配置文件angular.json的内容。要使用workspaces.readWorkspace,您必须首先从该树创建一个workspaces.WorkspaceHost。将以下代码添加到工厂函数中。functioncreateHost(tree:Tree):workspaces.WorkspaceHost{return{asyncreadFile(path:string):Promise{constdata=tree.read(path);if(!data){thrownewSchematicsException('找不到文件');}返回virtualFs.fileBufferToString(数据);},asyncwriteFile(path:string,data:string):Promise{returntree.overwrite(path,data);},asyncisDirectory(path:string):Promise{return!tree.exists(path)&&tree.getDir(path).subfiles.length>0;},asyncisFile(path:string):Promise{returntree.exists(path);},};}导出函数myService(options:MyServiceSchema):Rule{returnasync(tree:Tree)=>{consthost=createHost(tree);const{workspace}=awaitworkspaces.readWorkspace('/',host);};}workspaces是从@angular-devkit/core导出的,readWorkspace是其标准方法。此方法所需的第二个输入参数host从另一个自定义函数createHost返回。下面一行默认的逻辑处理:if(!options.project){options.project=workspace.extensions.defaultProject;}这个workspace.extensions属性包含一个defaultProject值,如果这个参数为不提供。如果在nggenerate命令中没有明确指定任何项目,我们将其用作后备值。获得项目名称后,使用它来检索指定项目的配置信息。constproject=workspace.projects.get(options.project);if(!project){thrownewSchematicsException(`无效的项目名称:${options.project}`);}constprojectType=project.extensions.projectType==='应用'?'app':'lib';options.path确定应用原理图后将原理图模板文件移动到哪里。原理图模式下的路径选项默认替换为当前工作目录。如果未定义路径,则使用项目配置中的sourceRoot和projectType确定。其逻辑体现在如下代码中:Rule可以获取外部模板文件,转换它们,并使用转换后的模板返回另一个Rule对象。您可以使用模板生成原理图所需的任何自定义文件。将以下代码添加到工厂函数中。consttemplateSource=apply(url('./files'),[applyTemplates({classify:strings.classify,dasherize:strings.dasherize,name:options.name}),move(normalize(options.pathasstring))]);apply()方法将对源代码应用多个规则并返回转换后的源代码。它有两个参数,一个源代码和一组规则。url()方法从文件系统中相对于原理图的路径读取源文件。applyTemplates()方法接受一个参数,其方法和属性在原理图模板和原理图文件名中可用。它返回一个规则。您可以在此处定义classify()和dasherize()方法,以及name属性。classify()方法接受一个值并以标题大小写返回该值。例如,如果提供的名称是我的服务,它将返回MyService。Titlecase类似于驼峰式大小写,是一种可变的拼写规则。dasherize()方法接受一个值并返回以破折号分隔的小写形式的值。例如,如果提供的名称是MyService,它将返回“my-service”的形式。应用原理图时,移动方法会将提供的源文件移动到目标位置。所以,我的服务被转化为MyService,而MyService又是my-service。规则工厂必须返回一个规则。返回链([mergeWith(templateSource)]);chain()方法允许您将多个规则组合成一个规则,以便可以在一个原理图中执行多个操作。在这里,您只是将模板规则与要由原理图执行的代码合并。至此,Angular库的Schematics已经开发完成。请继续关注Jerry的后续文章。我将介绍如何使用此Schematics。更多Jerry原创文章在这里:《王子熙》: