Monorepo dla Angular

Google, Facebook i Microsoft od dawna korzystaj z wielu aplikacji na jednym repozytorium. Taka praktyka przyśpiesza i ułatwia rozwój aplikacji. Załóżmy, że chcemy mieć swoją bibliotekę od UI i wykorzystywać ja w aplikacjach. W takich momentach przychodzi nam z pomocą narzędzie Nx od grupy Nrwl. Dzięki niemu możemy dodać aplikacje frontendowe i backendowe w jednym repozytorium. W tym artykule opiszemy aplikacje i biblioteki angularowe. W dobie zmieniających się technologi najlepiej używać nowoczesnych rozwiązań dlatego użycie Nx zapewni nam nowe rozwiązania. Dla przykładu, jeśli wygenerujemy aplikacje Angular, to przy okazji stworzą się też aplikacje do testów w popularnych technologia takich jak Cypress i Jest. Na kanale youtube Fireship możemy znaleźć bardziej uogólnione omownie Nx.

Stworzenie projektu

Do stworzenia projektu użyjemy Angular CLI 9. Poniżej list komend do wykonania w projekcie:

npx create-nx-workspace@latest nx-demo // tworzy workspace dla projektu nx-demo - w pierwszym kroku wybieramy empty project - w drugim kroku wybieramy Angular CLI
ng add @nrwl/angular --defaults // dodajemy funkcjonalność angular do projektu
ng g @nrwl/angular:application app1 // dodanie pierwszej aplikacji
ng g @nrwl/angular:application app2 // dodanie drugiej aplikacji
ng g @nrwl/angular:lib test-lib // dodanie biblioteki

Struktura folderów w aplikacji powinna wyglądać następująco:

apps
  |--app1
  |--app2
libs
  |--test-lib

Dodanie komponentu do biblioteki

W bibliotece dodajemy komponent o nazwie text-emoji.

ng g c text-emoji --project=test-lib

Następnie dodamy jeden Input(), dzięki któremu możemy przekazać string.

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'nx-demo-text-emoji',
  templateUrl: './text-emoji.component.html',
  styleUrls: ['./text-emoji.component.css']
})
export class TextEmojiComponent implements OnInit {
  @Input() text: string;
  
  constructor() { }
  
  ngOnInit(): void {}
}

W widoku do tekstu dodamy parę emoji.

<p>😎😎😎 {{ text }}</p>

Żeby móc skorzystać z komponentu w aplikacjach trzeba go dodać do modułu bilbioteki (NgModule). Dodajemy w sekcji declarations i exports.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TextEmojiComponent } from './text-emoji/text-emoji.component';

@NgModule({
  imports: [CommonModule],
  declarations: [TextEmojiComponent],
  exports: [TextEmojiComponent]
})

export class TestLibModule {}

Świetnie! Biblioteka gotowa.

Dodanie biblioteki do aplikacji

Aby aplikacja mogła skorzystać z biblioteki, należy ją dodać do modułów aplikacji (NgModule). W aplikacji app1 i app2 dodajemy bibliotekę TestLib.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { RouterModule } from '@angular/router';
import { TestLibModule } from '@nx-demo/test-lib';

@NgModule({
  declarations: [AppComponent],
  imports: [
    BrowserModule,
    RouterModule.forRoot([], { initialNavigation: 'enabled' }),
    TestLibModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})

export class AppModule {}

OK, ale skąd ten link @nx-demo/test-lib? Odpowiedź jest prosta, po dodaniu biblioteki nx automatycznie dodał do pliku tsconfig.json skróconą ścieżkę. Jeśli będziemy chcieli eksportować więcej plików z tego linku, należy edytować plik index.ts znajdujący się w katalogu biblioteki. Przejdźmy dalej i dodajmy komponent do naszych aplikacji. W aplikacji app1 w pliku app.component.html

<h1>This is application 1</h1>
<nx-demo-text-icon [text]="'application 1'"></nx-demo-text-icon>

Oraz w drugiej aplikacji app2 w pliku app.component.html

<h1>This is application 2</h1>
<nx-demo-text-icon [text]="'component in second app'"></nx-demo-text-icon>

Każda z aplikacji może korzystać z jednej biblioteki.

Jak to uruchomić?

Najprościej na localhost za pomocą CLI. Wpisujemy w konsoli komendy poniżej:

ng serve app1 // dla pierwszej aplikacji
ng serve app2 // dla drugiej aplikacji

Do stworzenia wersji produkcyjnej używamy komendy:

ng build app1

Rozpoznanie aplikacji w których były zmiany

Nasza aplikacja się rozrasta i w pewny momencie mamy 50 bibliotek i 5 aplikacji. Robimy zmiany w 5 bibliotekach, które są importowane do 2 aplikacji. W takim przypadku powinniśmy przetestować tylko 2 aplikacje, w których były zmiany. Na szczęście możemy coś takiego zobaczyć dzięki komendzie:

nx affected:apps

W terminalu zobaczymy które aplikacje wymagają przetestowania przed podniesieniem wersji. Możemy też zobrazować taki przykład na grafice. Wtedy korzystamy z komendy:

nx affected:dep-graph

Podsumowanie

Bardzo polecam korzystanie z nx w projektach monorepo. Ułatwia nam zarządzanie kodem. W powyższym przypadku dodaliśmy tylko bibliotekę i aplikacje angularowe, ale możliwe jest też dodanie np. apliacji React. Całość umieściłem na moim Github'ie.

Copyright © 2021 DevLuk