Создание Full-Stack приложений с использованием Angular CLI и Nx

Создание Full-Stack приложений с использованием Angular CLI и Nx

От автора: Nrwl Nx создал много приложений Angular, кодом которых поделился. Это сократило время создания общей библиотеки с нескольких дней до нескольких минут. Но как насчет обмена кодами между back-end и front-end? Наш последний релиз NX создавался с учетом этого варианта использования. В этой статье мы рассмотрим, как мы можем использовать Nx, чтобы произвести в Angular создание приложения в сочетании с сервисами API из библиотек многократного использования.

Видеть значит верить

Часто при описании Nx мы говорим о преимуществах монорепозиотриев, кривых зависимостей и расширенном статическом анализе. Однако в этом посте мы покажем, что вам не нужно изучать ни одного из этих факторов, чтобы максимально использовать Nx. Эти приемы помогут вам стать более эффективными, сразу же.

Начинаем с создания нового рабочего пространства

После того, как мы установили Nx, давайте создадим новое рабочее пространство.

create-nx-workspace myorg

Nx — это расширение для Angular CLI, поэтому create-nx-workspace просто запускает ng new myorg —collection=@nrwl/schematics и обрабатывает общие ошибки при использовании глобальных пакетов npm. Эта команда создаст для вас рабочее пространство.

apps/
libs/
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

Папки приложений и библиотек содержат все проекты в рабочем пространстве области.

app — это то, что мы можем запустить, либо в браузере, либо на сервере. Зачастую при создании приложения создается оптимизированный пакет. app нельзя использовать повторно в других app.

lib представляет собой многократно используемый фрагмент кода с четко определенным публичным API. Мы не можем запустить lib. Мы можем использовать ее только в другом lib или в app.

Создание приложений

Предположим, нам поручено создать приложение для управления тикетами. Мы можем начать с создания приложения, например: ng g app tuskdesk.

apps/ tuskdesk/ src/ app/ assets/ environments/ favicon.ico index.html main.ts polyfills.ts styles.css test.ts browserslist karma.conf.js tsconfig.app.json tsconfig.spec.json tslint.json tuskdesk-e2e/
libs/
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

Если вы использовали Angular CLI, все это должно выглядеть знакомо: одни и те же файлы конфигурации, одинаковые папки. Это потому, что при создании приложения Nx под капотом запускает команду CLI.

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

ng g app tuskdesk-admin

apps/ tuskdesk/ tuskdesk-e2e/ tuskdesk-admin/ tuskdesk-admin-e2e/
libs/
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

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

import { Component } from '@angular/core'; @Component({ selector: 'myorg-shell', template: ` <h1>Tuskdesk app!</h1> <div> <a href="learn-more">Learn more about Tuskdesk</a> <a href="learn-more-about-myorg">Learn more about MyOrg</a> Copyright stuff is in here as well. </div> `, styles: []
})
export class ShellComponent {
}

а также

import { Component } from '@angular/core'; @Component({ selector: 'myorg-shell', template: ` <h1>Tuskdesk admin app!</h1> <div> <a href="learn-more">Learn more about Tuskdesk</a> <a href="learn-more-about-myorg">Learn more about MyOrg</a> Copyright stuff is in here as well. </div> `, styles: []
})
export class ShellComponent {
}

vЭтот пример довольно причудливый, но он иллюстрирует важный момент. Это не редкость, когда мы имеем тот же компонент (или любой фрагмент кода), который используется в нескольких контекстах и приложениях.

Если бы мы разработали два приложения в двух отдельных репозиториях, извлечение двух компонентов оболочки в один многоразовый было бы затруднительным. Нам пришлось бы создать новый проект, настраивать тестирование, CI, развернуть его в приватном реестре npm и т. д. В результате мы, вероятно, решили бы не делать этого. Слишком сложно. При использовании Nx это вопрос нескольких минут.

Создание lib

В Nx мы совместно используем код с помощью libs. Итак, давайте создадим так называемый ui-shell.

ng g lib ui-shell apps/ tuskdesk/ tuskdesk-e2e/ tuskdesk-admin/ tuskdesk-admin-e2e/
libs/ ui-shell/ src/ lib/ ui-shell.module.ts ui-shell.module.spec.ts index.ts test.ts karma.conf.js tsconfig.lib.json tsconfig.spec.json tslint.json
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

Давайте обобщим наш компонент и переместим его в ui-shell.

import { Component } from '@angular/core'; @Component({ selector: 'myorg-shell', template: ` <h1>{{ title }}</h1> <div> <a href="learn-more">Learn more about Tuskdesk</a> <a href="learn-more-about-myorg">Learn more about Myorg</a> Copyright stuff is in here as well. </div> `, styles: []
})
export class ShellComponent { @Input() title: string;
}

apps/ tuskdesk/ tuskdesk-e2e/ tuskdesk-admin/ tuskdesk-admin-e2e/
libs/ ui-shell/ src/ lib/ shell.component.ts ui-shell.module.ts ui-shell.module.spec.ts index.ts test.ts karma.conf.js tsconfig.lib.json tsconfig.spec.json tslint.json
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

Наконец, мы можем обновить оба приложения, импортировав ui-shell lib и используя компонент.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core'; import { AppComponent } from './app.component';
import { NxModule } from '@nrwl/nx';
import { UiShellModule } from "@myorg/ui-shell"; @NgModule({ declarations: [AppComponent], imports: [BrowserModule, NxModule.forRoot(), UiShellModule], providers: [], bootstrap: [AppComponent]
})
export class AppModule {}

Извлечение этого компонента заняло всего несколько минут, и мы можем применить весь рефакторинг в одной передаче. Все в репозитории всегда будет последовательным: до и после рефакторинга.

Обращение к API

Но реальные приложения не существуют изолированно — им нужны API-интерфейсы для взаимодействия. Давайте создадим что-нибудь.

interface Ticket { id: number; title: string;
} @Component({ selector: 'myorg-root', template: ` <myorg-shell title="Tuskdesk App"></myorg-shell> <ul> <li *ngFor="let t of tickets|async"> {{ t.title }} </li> </ul> `
})
export class AppComponent { tickets: Observable<Ticket[]>; constructor(http: HttpModule) { this.tickets = http.get('/api/tickets'); }
}

Разработка API в рабочей области Nx была возможна всегда, но до Nx 6.4 она требовала много ручной настройки, поэтому немногие брались за это. Nx 6.4 изменил это (спасибо, Джейсону Джину за реализацию).

Создание приложений Node.js

Nx использует по умолчанию Karma для тестирования приложений и библиотек Angular. Это невозможно для приложений Node. Для этого мы решили использовать библиотеку jest. Чтобы настроить jest в рабочем пространстве, нам нужно запустить ng g jest. Это делается только один раз для рабочего пространства. Теперь давайте создадим приложение Node для API.

ng g node-app api apps/ tuskdesk/ tuskdesk-e2e/ tuskdesk-admin/ tuskdesk-admin-e2e/ api/ src/ app/ assets/ environemnts/ main.ts jest.config.js tsconfig.app.json tsconfig.spec.json tslint.json libs/ ui-shell/
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

И обновим main.ts, чтобы набросать простой сервис, возвращающий тикеты.

import * as express from 'express'; const app = express(); interface Ticket { id: number; title: string;
} const tickets: Ticket[] = [ { id: 1, title: 'Login page is broken' }, { id: 2, title: 'Everything is broken' }
]; app.get('/api/tickets', (req, res) => { res.send(JSON.stringify(tickets));
}); const port = 3333;
app.listen(port, (err) => { if (err) { console.error(err); } console.log(`Listening at http://localhost:${port}`);
});

После настройки прокси (см. здесь) мы можем запустить API (ng serve api) и приложение (ng serve tuskdesk). На этом этапе мы увидим наше приложение, отображающее данные.

У нас есть проблема. Мы определили ticket дважды: один раз в front-end, один раз в back-end. Это дублирование неизбежно приведет к тому, что два интерфейса не синхронизируются, а это означает, что будут возникать ошибки во время выполнения. Нам нужно разделить этот интерфейс.

Опять же, обычно совместное использование кода между front-end и back-end потребует нескольких дней работы, но с Nx это делается всего за несколько минут.

Совместное использование Libs Front-end и Back-end

ng g lib data — no-module — unit-test-runner=jest apps/ tuskdesk/ tuskdesk-e2e/ tuskdesk-admin/ tuskdesk-admin-e2e/ api/
libs/ data/ ui-shell/
tools/
angular.json
nx.json
package.json
tsconfig.json
tslint.json

Теперь мы можем переместить интерфейс Ticket в библиотеку данных и обновить front-end и back-end.

import { Component } from '@angular/core';
import {Observable} from "rxjs";
import {HttpClient} from "@angular/common/http";
import {Ticket} from "@myorg/data"; @Component({ selector: 'myorg-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css']
})
export class AppComponent { tickets: Observable<Ticket[]>; constructor(http: HttpClient) { this.tickets = http.get<Ticket[]>('/api/tickets'); }
}

import * as express from 'express';
import {Ticket} from "@myorg/data"; const app = express(); const tickets: Ticket[] = [ { id: 1, title: 'Login page is broken' }, { id: 2, title: 'Everything is broken' }
]; app.get('/api/tickets', (req, res) => { res.send(JSON.stringify(tickets));
}); const port = 3333;
app.listen(port, (err) => { if (err) { console.error(err); } console.log(`Listening at http://localhost:${port}`);
});

Nx — умен

Мы уже показали вам удивительные вещи. У нас есть репозиторий, где мы можем создавать несколько приложений Angular и Node.js и совместно использовать код. И это заняло у нас всего несколько минут.

Но Nx может сделать намного больше. Он знает, как ваши приложения и библиотеки зависят друг от друга. Чтобы продемонстрировать это, давайте запустим npm run dep-graph, и вы увидите что-то вроде этого:

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

Если мы запускаем, скажем, npm run affected:test —base=master, вы будете тестировать только те проекты, на которые могут повлиять изменения в вашем ответвлении.

Если мы, например, изменим библиотеку данных, API и приложения tuskdesk будут повторно протестированы, а приложение tuskdesk-admin — нет, так как оно не содержит зависимостей от данных. Существуют аналогичные команды для построения, запуска тестов e2e и т. д. Обратите внимание, что все это работает для front-end/back-end.

Попробуйте!

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

Посмотрите этот бесплатный курс, чтобы узнать больше: курс. И попробуйте его. Вы также можете найти полную реализацию данного примера в этом репозитории.

Автор: Victor Savkin

Источник: https://blog.nrwl.io/

Редакция: Команда webformyself.