У вас включен AdBlock или иной блокировщик рекламы.

Пожалуйста, отключите его, доход от рекламы помогает развитию сайта и появлению новых статей.

Спасибо за понимание.

В другой раз
DevGang блог о програмировании
Авторизоваться

Angular: автоматизация шаблонов schematics

Schematics - один из самых сильных инструментов Angular для быстрой генерации шаблонов и поддержания стандартов кода. К сожалению, может быть трудно создавать и использовать схемы. В этой статье я продемонстрирую свой способ разработки и использования схем, в основном сосредоточив внимание на том, как интегрировать и отлаживать его как часть проекта нашего приложения, и быстро получить некоторые сильные преимущества схем.

Создаем нашу первую команду Schematics

Прежде чем мы начнем, чтобы создать проект схемы, мы должны установить CLI:

npm install -g @angular-devkit/schematics-cli

Теперь мы можем использовать CLI и просто генерировать новые схемы для нашего проекта:

schematics blank my-project-schematics

Эта команда создала пустой проект схемы в папке «my-project-schematics».

Теперь мы готовы приступить к созданию наших первых схем.

Давайте начнем с создания простой команды «hello world». Мы делаем это, определяя команды в файле с именем collection.json

"hello": {
 "description": "Hello schematics.",
 "factory": "./hello/index",
 "schema": "./hello/schema.json"
}

Как вы могли заметить, наше определение содержит две ссылочные записи: файл factory, который будет использоваться в качестве точки входа для нашей команды schematics, и schema, который определяет детали и свойства нашей команды и используется IDE для деталезации и автозаполнения.

Давайте начнем с определения нашей схемы:

{
 "id": "HelloSchematics",
 "title": "Hello My Schematics Project",
 "type": "object",
 "properties": {
   "name": {
     "type": "string",
     "description": "The name of whom to say hello to.",
     "$default": {
       "$source": "argv",
       "index": 0
     }
   }
 },
 "required": []
}

Теперь factory файл:

import {Rule} from '@angular-devkit/schematics';

export default function(options: {name: string}): Rule {
 return () => {
   console.log('hello from:', options.name);
 };
}

Пока все хорошо, теперь у нас есть первая команда генерации! Итак, давайте попробуем запустить нашу команду.

Для этого добавьте следующую команду в скрипты в основном файле `package.json`:

schematics:watch”: “cd ./my-project-schematics/ && npm link && cd .. && npm link my-project-schematics && npm run build --prefix ./my-project-schematics -- --watch”

Эта команда создает символическую ссылку на папку node_modules нашего проекта, а затем устанавливает шаг сборки для запуска в режиме наблюдения, чтобы он автоматически перестраивался при внесении изменений.

Теперь мы готовы и должны быть в состоянии сформировать нашу команду hello. Давайте выполним:

ng generate my-project-schematics:hello Itay

Совет: мы можем установить наши схемы как схемы по умолчанию в angular.json, так что нам не нужно будет указывать имя схемы каждый раз, когда мы его используем.

После того, как мы протестировали нашу новую сгенерированную команду, давайте продолжим ее разработку, чтобы она генерировала файл hello.md.

Для этого в нашей папке команд мы добавляем файл files/hello.md с таким содержимым:

Hello From <%= name %>!

И теперь в index.ts мы можем обработать этот файл и выполнить нашу команду.

import {Rule, SchematicContext, Tree, apply, mergeWith, template, url, move} from '@angular-devkit/schematics';

export default function(options: {name: string}): Rule {
 return (host: Tree, context: SchematicContext) => {
  // process "hello.md".
  const templateSource = apply(url('./files'), [
     // pass our options variables to the template.
     template({
       ...options
     })
   ]);
  return mergeWith(templateSource)(host, context);
 };
}

Теперь, если мы запустим снова, ng generate my-project-schematics:hello Itay у нас должен сгенерироваться файл hello.md.

Мы сделали нашу первую команду в schematics! Теперь мы узнаем, как установить ее в проекте, таким образом, чтобы каждый член команды мог его использовать.

Во-первых, нам нужно добавить еще один скрипт в package.json:

“schematics:install”: “npm run build -- prefix ./my-project-schematics && npm i ./my-project-schematics”

Теперь, чтобы убедиться, что все, кто устанавливает наш проект, также получат наши схемы, мы можем использовать npm ловушку postinstall и запустить наш скрипт установки.

В разделе scripts добавляем:

"postinstall": "npm run schematics:install"

Теперь каждый раз, когда кто-то устанавливает наши зависимости, наш скрипт запускается и автоматически устанавливает схемы.

Использовать внешние схемы

Пока что мы создали базовый пример схемы. Теперь давайте расширим его и посмотрим, как мы можем быстро получить еще больше его преимуществ.

В этом примере мы будем использовать схемы из NgRx в сочетании со схемами Angular.

Сначала установите в проект схемы @ngrx/schematics и @schematics/angular:

npm i @ngrx/schematics @schematics/angular --save

Итак, теперь мы готовы начать писать нашу команду.

Мы будем использовать еще одну замечательную особенность схем, которая позволит нам расширять схемы externalSchematic.

Как и ранее, добавьте в collection.json следующее:

"feature": {
 "description": "Complete NgRx and Angular feature.",
 "factory": "./feature/index",
 "schema": "./feature/schema.json"
}

Теперь в файле ./feature/index мы можем объединить внешние команды Angular и NgRx, чтобы создать свою собственную реализацию.

import {Rule, Tree, SchematicContext, chain, externalSchematic} from '@angular-devkit/schematics';
import {Schema as NgrxContainer} from '@ngrx/schematics/src/container/schema';
import {Schema as NgrxFeatureOptions} from '@ngrx/schematics/src/feature/schema';
import {Schema as ModuleOptions} from '@schematics/angular/module/schema';

export default function(options: { name: string; path?: string }): Rule {
 return (host: Tree, context: SchematicContext) => {

   return chain([
     externalSchematic('@schematics/angular', 'module', {
       ...options,
       flat: false
     } as ModuleOptions),
     externalSchematic('@ngrx/schematics', 'container', {
       ...options,
       module: options.name,
       flat: false
     } as NgrxContainer),
     externalSchematic('@ngrx/schematics', 'feature', {
       ...options,
       flat: false,
       module: options.name,
       creators: true
     } as NgrxFeatureOptions)
   ])(host, context);
 };
}

Теперь, после выполнения команды, ng generate feature my-feature должны будут сгенерироваться следующие файлы:

Совет: Вы можете добавить свойство extend в файл collection.json, который добавит наши схемы для других команд “extends”: [“@ngrx/schematics”].

Поэтому теперь каждый раз, когда мы хотим использовать команды из внешних схем, нам не нужно указывать имя схемы.

Бонус, тестирование с Jest

Как вы могли заметить, проект схемы уже был создан с помощью инфраструктуры тестирования и Jasmine - как инструмент тестирования.

Лично я бы порекомендовал вам использовать Jest в основном из-за его снапшотов, которые позволяют нам легко писать и обновлять наши тесты, в то же время получая возможность мгновенно видеть результат схемы.

Теперь, чтобы протестировать нашу функцию, нам сначала нужно будет создать настроку, которая будет генерировать рабочее пространство в каждом тесте и предоставлять нам инфраструктуру, необходимую для нашей функции. Мы создаем файл utils/workspace.ts.

import {
 UnitTestTree,
 SchematicTestRunner,
} from '@angular-devkit/schematics/testing';

export const defaultWorkspaceOptions = {
 name: 'workspace',
 newProjectRoot: 'projects',
 version: '8.0.0',
 defaultProject: 'bar',
};

export const defaultAppOptions = {
 name: 'bar'
};

const defaultLibOptions = {
 name: 'baz'
};

export function getTestProjectPath(
 workspaceOptions: any = defaultWorkspaceOptions,
 appOptions: any = defaultAppOptions
) {
 return `/${workspaceOptions.newProjectRoot}/${appOptions.name}`;
}

export function createWorkspace(
 schematicRunner: SchematicTestRunner,
 appTree: UnitTestTree,
 workspaceOptions = defaultWorkspaceOptions,
 appOptions = defaultAppOptions,
 libOptions = defaultLibOptions
) {
 appTree = schematicRunner.runExternalSchematic(
   '@schematics/angular',
   'workspace',
   workspaceOptions
 );
 appTree = schematicRunner.runExternalSchematic(
   '@schematics/angular',
   'application',
   appOptions,
   appTree
 );
 appTree = schematicRunner.runExternalSchematic(
   '@schematics/angular',
   'library',
   libOptions,
   appTree
 ); return appTree;
}

Для установки, мы будем использовать SchematicTestRunner из @angular-devkit/schematics/testing который позволяет вызывать команды схемы и наш createWorkspace что позволит создать объект tree, который нам нужно для нашей инфраструктуры.

Наконец, для теста мы запустим нашу команду, используя, SchematicTestRunner а затем мы будем использовать результат, чтобы просто прочитать содержимое нашей команды и ожидать, что он будет соответствовать нашему снапшоту.

import { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing';
import * as path from 'path';
import {
 getTestProjectPath,
 createWorkspace,
 defaultWorkspaceOptions,
 defaultAppOptions
} from '../utils/create-workspace';

const collectionPath = path.join(__dirname, '../collection.json');

describe('Feature', () => {
 const schematicRunner = new SchematicTestRunner('schematics', collectionPath); let appTree: UnitTestTree; beforeEach(() => {
   appTree = createWorkspace(schematicRunner, appTree);
 });

 it('should create a proper module', () => {
   const options = {
     name: 'foo',
     project: 'baz'
   };
   const specifiedProjectPath = getTestProjectPath(defaultWorkspaceOptions, {
     ...defaultAppOptions,
     name: 'baz'
   });
   const tree = schematicRunner.runSchematic('feature', options, appTree);
   const content = tree.readContent(`${specifiedProjectPath}/src/lib/foo/foo.module.ts`);   expect(content).toMatchSnapshot();
 });
});

Резюме

Мы узнали, как разработать проект схемы и установить его в нашем проекте. Мы использовали одну из интересных функций schematics для сокращения наших шаблонов путем создания команды.

Наконец, мы узнали о быстром и эффективном способе тестирования наших схем, используя jest и настроили рабочее пространство для тестов.

#Angular