您好,我叫Maxim。 几年来,我一直在进行前端开发。 我经常不得不处理各种HTML模板的布局。 在日常工作中,我通常使用带有自定义pug模板引擎的webpack构建器,并且还使用BEM方法。 为了使我的生活更轻松,我使用了一个精美的包装 。
最近,我需要在Angular上做一个小项目,并且由于我习惯了使用自己喜欢的工具,所以我不想回到纯HTML上。 在这方面,出现了一个问题,即如何用某个角度结交bempug朋友,不仅要结交朋友,还需要用cli生成具有所需结构的组件。
谁在乎我是如何做到的,欢迎来爱猫。
首先,创建一个测试项目,在该项目上我们将测试模板。
我们在命令行执行:
ng g test-project
。
在设置中,我选择了scss预处理程序,因为使用它更方便。
该项目已创建,但是html中的默认组件模板现已修复。 首先,您需要使用pug模板引擎结识cli朋友,为此,我使用了ng-cli-pug-loader软件包
安装软件包,为此,请转到项目文件夹并执行:
ng add ng-cli-pug-loader
。
现在,您可以使用哈巴狗模板文件。 接下来,我们将AppComponent组件的根装饰器重写为:
@Component({ selector: 'app-root', templateUrl: './app.component.pug', styleUrls: ['./app.component.scss'] })
因此,我们将文件扩展名app.component.html更改为app.component.pug,并且内容以模板语法编写。 在此文件中,我删除了除路由器以外的所有内容。
最后,让我们开始创建组件生成器!
要生成模板,我们需要创建自己的方案。 我正在使用@ angle-devkit中的diagrams-cli包。 使用以下命令全局安装软件包:
npm install -g @angular-devkit/schematics-cli
。
我使用以下命令在项目外部的单独目录中创建了方案:
schematics blank --name=bempug-component
。
我们进入创建的方案,现在对src / collection.json文件感兴趣。 看起来像这样:
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json", "schematics": { "bempug-component": { "description": "A blank schematic.", "factory": "./bempug-component/index#bempugComponent" } } }
这是我们方案的描述文件,其中参数为“ factory”:“ ./bempug-component/index#bempugComponent”:这是生成器“ factory”主要功能的描述。
最初,它看起来像这样:
import { Rule, SchematicContext, Tree } from '@angular-devkit/schematics';
您可以默认使函数导出,然后可以将“ factory”参数重写为“ ./bempug-component/index”。
接下来,在方案的目录中,创建文件schema.json,它将描述方案的所有参数。
{ "$schema": "http://json-schema.org/schema", "id": "SchemanticsForMenu", "title": "Bempug Schema", "type": "object", "properties": { "name": { "type": "string", "$default": { "$source": "argv", "index": 0 } }, "path": { "type": "string", "format": "path", "description": "The path to create the component.", "visible": false }, "project": { "type": "string", "description": "The name of the project.", "$default": { "$source": "projectName" } } } }
参数位于属性中,即:
- 名称实体名称(在我们的例子中将是组件);
- 路径是生成器用来创建组件文件的路径;
- 项目是项目本身,将在其中生成组件。
将更多参数添加到将来需要的文件中。
"module": { "type": "string", "description": "The declaring module.", "alias": "m" }, "componentModule": { "type": "boolean", "default": true, "description": "Patern module per Component", "alias": "mc" }, "export": { "type": "boolean", "default": false, "description": "Export component from module?" }
- 这里的模块将存储指向其中将包含组件的模块或组件模块的链接;
- componentModule有一个标志是否为组件创建自己的模块(然后我得出结论,它将始终被创建并将其设置为true);
- 导出:这是是否从要导入组件模块的模块中导出的标志;
接下来,我们使用组件的参数schema.d.ts文件创建一个接口。
export interface BemPugOptions { name: string; project?: string; path?: string; module?: string; componentModule?: boolean; module?: string; export?: boolean; bemPugMixinPath?: string; }
在其中,属性复制了schema.json中的属性。 接下来,准备我们的工厂,转到index.ts文件。 在其中,我们创建两个filterTemplates函数,这些函数将负责根据componentModule的值为组件创建一个模块,以及setupOptions,这将设置工厂所需的参数。
function filterTemplates(options: BemPugOptions): Rule { if (!options.componentModule) { return filter(path => !path.match(/\.module\.ts$/) && !path.match(/-item\.ts$/) && !path.match(/\.bak$/)); } return filter(path => !path.match(/\.bak$/)); } function setupOptions(options: BemPugOptions, host: Tree): void { const workspace = getWorkspace(host); if (!options.project) { options.project = Object.keys(workspace.projects)[0]; } const project = workspace.projects[options.project]; if (options.path === undefined) { const projectDirName = project.projectType === 'application' ? 'app' : 'lib'; options.path = `/${project.root}/src/${projectDirName}`; } const parsedPath = parseName(options.path, options.name); options.name = parsedPath.name; options.path = parsedPath.path; }
接下来,我们编写main函数:
export function bempugComponent(options: BemPugOptions): Rule { return (host: Tree, context: SchematicContext) => { setupOptions(options, host); const templateSource = apply(url('./files'), [ filterTemplates(options), template({ ...strings, ...options }), move(options.path || '') ]); const rule = chain([ branchAndMerge(chain([ mergeWith(templateSource), ])) ]); return rule(host, context); } }
工厂已经准备就绪,它可以通过处理files文件夹中的模板来生成组件文件,该文件夹尚不可用。 没关系,就我而言,我们在方案文件夹中创建一个bempug-component文件文件夹。 在文件文件夹中,创建文件夹__name@dasherize__
,在生成过程中,工厂将__name@dasherize__
替换为组件名称。
接下来,在__name@dasherize__
创建文件
__name@dasherize__
帕格组件模板__name@dasherize__
组件的单元测试文件- 组件本身的
__name@dasherize__
文件 __name@dasherize__
组件模块__name@dasherize__
组件样式表
现在,我们将向工厂添加对更新模块的支持,为此,我们将创建add-to-module-context.ts文件,以存储工厂使用该模块所需的参数。
import * as ts from 'typescript'; export class AddToModuleContext {
将模块支持添加到工厂。
const stringUtils = { dasherize, classify };
现在,将-m <模块参考>参数添加到cli命令时,我们的组件模块将在指定的模块中添加导入,并在添加–export标志时从其添加导出。 接下来,我们添加BEM支持。 为此,我获取了npm bempug包的源代码,并将代码制作在一个bempugMixin.pug文件中,该文件放置在common文件夹中,并放置在另一个common文件夹中,以便将mixin复制到有角度的项目中的common文件夹中。
我们的任务是在每个模板文件中都连接该mixin,并且在生成新组件时不进行重复,为此,我们将此功能添加到了工厂中。
import { Rule, SchematicContext, Tree, filter, apply, template, move, chain, branchAndMerge, mergeWith, url, SchematicsException } from '@angular-devkit/schematics'; import {BemPugOptions} from "./schema"; import {getWorkspace} from "@schematics/angular/utility/config"; import {parseName} from "@schematics/angular/utility/parse-name"; import {normalize, strings} from "@angular-devkit/core"; import { AddToModuleContext } from './add-to-module-context'; import * as ts from 'typescript'; import {classify, dasherize} from "@angular-devkit/core/src/utils/strings"; import {buildRelativePath, findModuleFromOptions, ModuleOptions} from "@schematics/angular/utility/find-module"; import {addExportToModule, addImportToModule} from "@schematics/angular/utility/ast-utils"; import {InsertChange} from "@schematics/angular/utility/change"; const stringUtils = { dasherize, classify };
是时候开始填写我们的模板文件了。
__name@dasherize__.component.pug
:
include <%= bemPugMixinPath %> +b('<%= name %>') +e('item', {m:'test'}) | <%= name %> works
生成期间在<%=%>中指定的内容将替换为组件名称。
__name@dasherize__.component.spec.ts:
import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import {NO_ERRORS_SCHEMA} from '@angular/core'; import { <%= classify(name) %>ComponentModule } from './<%= name %>-component.module'; import { <%= classify(name) %>Component } from './<%= name %>.component'; describe('<%= classify(name) %>Component', () => { let component: <%= classify(name) %>Component; let fixture: ComponentFixture<<%= classify(name) %>Component>; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [<%= classify(name) %>ComponentModule], declarations: [], schemas: [ NO_ERRORS_SCHEMA ] }) .compileComponents(); })); beforeEach(() => { fixture = TestBed.createComponent(<%= classify(name) %>Component); component = fixture.componentInstance; fixture.detectChanges(); }); it('should create', () => { expect(component).toBeTruthy(); }); });
在这种情况下,<%= classify(name)%>用于将名称转换为CamelCase。
__name@dasherize__.component.ts:
import { Component, OnInit, ViewEncapsulation} from '@angular/core'; @Component({ selector: 'app-<%=dasherize(name)%>-component', templateUrl: '<%=dasherize(name)%>.component.pug', styleUrls: ['./<%=dasherize(name)%>-component.scss'], encapsulation: ViewEncapsulation.None }) export class <%= classify(name) %>Component implements OnInit { constructor() {} ngOnInit(): void { } }
__name@dasherize__-component.module.ts:
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import {<%= classify(name) %>Component} from './<%= name %>.component'; @NgModule({ declarations: [ <%= classify(name) %>Component, ], imports: [ CommonModule ], exports: [ <%= classify(name) %>Component, ] }) export class <%= classify(name) %>ComponentModule { }
__name@dasherize__-component.scss:
.<%= name %>{ }
我们使用命令``npm run build''来构建方案。
一切准备就绪,可以在项目中生成组件!
要进行检查,请返回我们的Angular项目并创建一个模块。
ng gm test-schema
接下来,我们执行``npm link <绝对路径到带有我们scheme的项目文件夹>'',以便将我们的scheme添加到项目的node_modules。
然后,我们使用ng g bempug-component:bempug-component test -m /src/app/test-schema/test-schema.module.ts –export
尝试电路ng g bempug-component:bempug-component test -m /src/app/test-schema/test-schema.module.ts –export
。
我们的方案将创建一个组件,并通过export将其添加到指定的模块中。
该方案已准备就绪,您可以开始使用熟悉的技术制作该应用程序。
您可以在此处查看最终版本,该软件包也可在npm中获得 。
在创建方案时,我使用了有关该主题的文章,对作者表示感谢。
感谢您的关注,读到最后的每个人,您都是最好的!
而另一个激动人心的项目正等着我。 待会见!