Små Angular-applikationsprojekter i Nx-arbejdsområder

Forsidebillede af John Moeses Bauan på Unsplash.

Original udgivelsesdato:2020-03-23.

I Nx-arbejdsområder kan vi følge en strategi om at holde vores Angular-applikationsprojekter så små som muligt for at have færre grunde til at ændre applikationsprojektet og muliggøre genbrug af almindelig kode. Det gør vi ved at indkapsle forretningslogik og konfiguration i arbejdsrumsbiblioteker.

En taktik ved denne strategi er at bruge et af shell-biblioteksmønstrene til orkestrering af initialisering, konfiguration og routing. For arbejdsområder med en enkelt applikation som denne er et feature shell-bibliotek et godt valg.

Denne shell-biblioteksvariant er også den, der bevarer den mindste mængde logik i applikationsprojektet, hvilket er meget velegnet til vores formål. Vi vil dog ikke gennemgå oprettelsen af ​​denne type bibliotek i denne artikel.

Lad os i stedet sætte skub i dette ved at udtrække arbejdsområdebiblioteker til statiske aktiver, stilarter og miljøer.

Vi gennemgår kommandoerne og trinene for at konfigurere et komplet Nx Angular-arbejdsområde og anvender en lille applikationsprojektstrategi. Bagefter vil vi diskutere fordelene ved de forskellige taktikker og teknikker, vi bruger til at anvende den lille applikationsprojektstrategi.

Opret et Nx-arbejdsområde med en Angular-applikation

For at demonstrere dette opretter vi et Nx-arbejdsområde med en enkelt Angular-applikation. Udfør kommandoerne i liste 1.

npx create-nx-workspace workspace --cli=angular --preset=angular --appName=tiny-app --style=scss

nx update @angular/cli @angular/core

Vi opretter arbejdsområdebiblioteker, som applikationen kan importere gennem @workspace omfang.

Udpak et aktivarbejdsområdebibliotek

Når vi genererer en Angular-applikation, kommer den med en tom assets mappe til statiske filaktiver såsom ikoner, billeder og webskrifttyper. Vi kan referere til disse aktiver fra DOM-elementattributter og typografiark ved at bruge absolutte stier, for eksempel <img src="/assets/images/logo.png" /> og .twitter { background-image: url('/assets/icons/twitter.png'); } .

Genererede Angular-applikationer kommer også med den statiske fil favicon.ico som der henvises til i index.html . Vi genererer et aktivarbejdsområdebibliotek, udtrækker vores statiske aktiver til det, konfigurerer arbejdsområdet og opdaterer referencer for at bruge aktivbiblioteket.

Generer et rent arbejdsområdebibliotek

Det første trin er at generere et arbejdsområdebibliotek og rydde op i det, da det ikke vil indeholde TypeScript-filer, kun statiske filer.

nx generate library assets --directory=shared --tags="scope:shared,type:assets" --style=scss

npx rimraf ./apps/tiny-app/src/assets ./libs/shared/assets/*.js ./libs/shared/assets/*.json ./libs/shared/assets/src/*.* ./libs/shared/assets/src/lib

"# shared-assets" > ./libs/shared/assets/README.md

Udfør kommandoerne i liste 2, og rediger derefter angular.json for at fjerne alle arkitektmål fra shared-assets projekt for at matche konfigurationsstrukturen i liste 3.

{
  "//": "angular.json",
  "projects": {
    "shared-assets": {
      "architect": {}
    }
  }
}

Opsæt mapper med almindelige aktiver, og flyt faviconet

Nu hvor vi har en ren arbejdsområdebiblioteksmappestruktur, lad os oprette fælles aktiver-mapper og flytte favicon-filen til vores aktiverbibliotek ved at udføre kommandoerne i Listing 4.

npx mkdirp ./libs/shared/assets/src/assets/fonts ./libs/shared/assets/src/assets/icons ./libs/shared/assets/src/assets/images

"" > ./libs/shared/assets/src/assets/fonts/.gitkeep

"" > ./libs/shared/assets/src/assets/icons/.gitkeep

"" > ./libs/shared/assets/src/assets/images/.gitkeep

mv ./apps/tiny-app/src/favicon.ico ./libs/shared/assets/src

For at konfigurere Angular-applikationsprojektet til at bruge aktiverne i arbejdsområdebiblioteket, navigerer vi til tiny-app:build arkitektmål i angular.json og erstat assets muligheder med posterne i liste 5.

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "options": {
            "assets": [
              {
                "glob": "favicon.ico",
                "input": "libs/shared/assets/src",
                "output": "./"
              },
              {
                "glob": "**/*",
                "input": "libs/shared/assets/src/assets",
                "output": "assets"
              }
            ]
          }
        }
      }
    }
  }
}

Vi instruerer Angular CLI om at kopiere favicon-filen til dist/apps/tiny-app mappe, når du bygger applikationen. Derudover alle filer og mapper i libs/shared/assets/src/assets mappen kopieres til dist/apps/tiny-app/assets ved byggeprocessen. Dette vil holde vores applikations aktiver-links i drift i vores ikke-lokale miljøer, såsom vores iscenesættelse og produktionswebservere.

Prøv det lokalt

Gå videre, prøv det lokalt med nx serve --open på Webpack-udviklingsserveren. Udfør kommandoerne i liste 6 for at bygge et produktionsprogrampakke og betjene det ved hjælp af en lokal statisk webserver. Sørg for, at favicon vises begge steder.

nx build --prod

npx http-server dist/apps/tiny-app -o

Samle et aktiv

Nx-genererede Angular-applikationer viser et Nx-logo i deres app-komponent, som det ses øverst i figur 1.

Hvis vi åbner app.component.html , ser vi, at logoet er linket fra https://nx.dev/assets/images/nx-logo-white.svg .

Lad os gøre logoet til en del af vores applikationspakke ved at inkludere det i vores aktivbibliotek og opdatere billedattributten i app-komponentens skabelon.

Udfør kommandoen i liste 7 for at downloade Nx-logoet og gemme det i aktivbiblioteket.

npx -p wget-improved nwget https://nx.dev/assets/images/nx-logo-white.svg -O ./libs/shared/assets/src/assets/images/nx-logo-white.svg

Lad os nu opdatere billedelementet for at referere til logoet fra vores aktivbibliotek. Rediger app.component.html som vist i liste 8.

<!-- app.component.html -->
<img
  alt="Nx logo"
  width="75"
  src="/assets/images/nx-logo-white.svg"
/>

Det er det. Vi udpakkede et aktivarbejdsområdebibliotek og bundtede statiske filer. Prøv det en gang til for at sikre dig, at alt er konfigureret korrekt.

Udpak et stilarbejdsområdebibliotek

Vinkelapplikationer genereres med et globalt typografiark kaldet styles.css eller i vores tilfælde styles.scss da vi bruger Sass. Det globale typografiark kan indeholde generiske typografier, elementtypetypografier, CSS-objekter og hjælpetypografier.

Et globalt stylesheet bliver større og mere komplekst, efterhånden som en applikation udvikler sig. Når vi bruger Sass, kan vi opdele et typografiark i Sass-partialer, som sædvanligvis har navne foran med en understregning (_ ), for eksempel _global.scss .

Sass-partialer er bundtet ved hjælp af import-sætninger, for eksempel @import './lib/global'; . Bemærk, at Sass bruger konvention til at finde filen, uanset om dens navn har et understregningspræfiks eller ej.

I modsætning til vanilla CSS, indlæses Sass' importerklæringer ikke en ad gangen, asynkront. I hvert fald ikke når vi refererer til vores applikations statiske aktiver. I stedet er de samlet i et enkelt stylesheet. Dette svarer til, hvordan vi er vant til værktøjer som Webpack og Browserify, der samler JavaScript- og TypeScript-filer.

Vi vil gøre vores Angular-applikationsprojekt mindre ved at udtrække et bibliotek med stilarter, konvertere styles.scss til en Sass-del, bundter den som en del af et arbejdsområdebiblioteksstilark og konfigurer vores applikationsprojekt til at linke til dette typografiark.

Generer et rent arbejdsområdebibliotek

Som vi gjorde i et tidligere kapitel, starter vi med at generere et arbejdsområdebibliotek og rydde op i det, da det kun vil indeholde typografiark, ikke TypeScript-filer.

nx generate library styles --directory=shared --tags="scope:shared,type:styles" --style=scss

npx rimraf ./libs/shared/styles/*.js ./libs/shared/styles/*.json ./libs/shared/styles/src/*.* ./libs/shared/styles/src/lib/*.*

"# shared-styles" > ./libs/shared/styles/README.md

Udfør kommandoerne i liste 9, og rediger derefter angular.json for at fjerne alle arkitektmål fra shared-styles projekt for at matche konfigurationsstrukturen i liste 10.

{
  "//": "angular.json",
  "projects": {
    "shared-styles": {
      "architect": {}
    }
  }
}

Opsæt et indgangsstilark

Med en ren mappestruktur på arbejdsområdet er vi klar til at oprette en index.scss stylesheet, der vil tjene som indgang til vores bibliotek med stilarter.

Samtidig konverterer vi applikationstypografiarket (styles.scss ) til en Sass-partial ved at omdøbe den og flytte den ind i stilbiblioteket. Dette gøres ved at udføre kommandoerne i liste 11.

mv ./apps/tiny-app/src/styles.scss ./libs/shared/styles/src/lib/_global.scss

"@import './lib/global';" > ./libs/shared/styles/src/index.scss

Kun én ting tilbage at gøre. Rediger angular.json for at erstatte styles mulighed for tiny-app:build arkitektmål med posten, der ses i strukturen af ​​Listing 12A.

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "options": {
            "styles": [
              "libs/shared/styles/src/index.scss"
            ]
          }
        }
      }
    }
  }
}

Bemærk, at hvis vi bruger Karma og skriver komponenttest, der er afhængige af globale stilarter, bliver vi nødt til at tilføje en lignende mulighed til test arkitektmål for vores UI-arbejdsområdebiblioteker som vist i eksemplet i Listing 12B.

{
  "//": "angular.json",
  "projects": {
    "ui-buttons": {
      "architect": {
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "options": {
            "styles": [
              "libs/shared/styles/src/index.scss"
            ]
          }
        }
      }
    }
  }
}

Hvis et brugergrænsefladebibliotek deles mellem flere apps og har tests, der er afhængige af deres individuelle globale stilarter, er vi nødt til at oprette flere test konfigurationer for det pågældende projekt som vist i liste 12C.

{
  "//": "angular.json",
  "projects": {
    "ui-buttons": {
      "architect": {
        "test": {
          "builder": "@angular-devkit/build-angular:karma",
          "configuration": {
            "booking": {
              "styles": [
                "libs/booking/shared/styles/src/index.scss"
              ]
            },
            "check-in": {
              "styles": [
                "libs/check-in/shared/styles/src/index.scss"
              ]
            }
          }
        }
      }
    }
  }
}

Prøv det lokalt

Angular CLI linker nu index.scss i index.html , både lokalt på udviklingsserveren og i vores implementerede miljøer, hvor typografiarket er en del af applikationspakken.

Sørg for at prøve det. Tilføj globale typografier, og bekræft, at de er anvendt.

nx build --prod

npx http-server dist/apps/tiny-app -o

Kør nx serve --open at teste globale stilarter lokalt eller køre kommandoerne i Listing 6 for at betjene en produktionspakke på en lokal statisk webserver.

Udpak et miljøarbejdsområdebibliotek

Før vi bootstrapper vores Angular-applikation i main.ts , kalder vi betinget enableProdMode baseret på om den boolske production egenskaben for environment objekt er indstillet eller ryddet.

Kører enableProdMode deaktiveret yderligere registreringscyklusser for ændring af driftstid i produktionstilstand. I udviklingstilstand er denne ekstra cyklus det, der udløser ExpressionChangedAfterItHasBeenCheckedError advarsel.

Yderligere runtime-påstande fremsættes i hele kernedelene af selve Angular i udviklingstilstand.

Generer et arbejdsområdebibliotek

Selvom det arbejdsområdebibliotek, vi vil udpakke, bliver lille og meget specialiseret, indeholder det TypeScript, så lint og test arkitektmål er stadig nyttige.

nx generate library environments --directory=shared --tags="scope:shared,type:environments" --style=scss

npx rimraf ./libs/shared/environments/src/lib/*.*

Liste 13 viser, at vi først genererer miljøbiblioteket. Derefter fjerner vi filerne genereret i src/lib undermappe til biblioteket.

Flyt miljøfilerne og konfigurer applikationsafhængigheder

Med en tom lib mappe i vores miljøbibliotek, lad os flytte miljøfilerne fra applikationsprojektet, eksponere dem gennem bibliotekets indgangspunkt og til sidst slette environments mappe for ansøgningsprojektet. Det hele gøres ved at udføre kommandoerne i liste 14.

mv ./apps/tiny-app/src/environments/*.* ./libs/shared/environments/src/lib

"export * from './lib/environment';" > ./libs/shared/environments/src/index.ts

npx rimraf ./apps/tiny-app/src/environments

For at konfigurere Angular-applikationsprojektet til at bruge en miljøfil i arbejdsområdebiblioteket baseret på build-konfigurationen, navigerer vi til tiny-app:build arkitektmål i angular.json og erstat fileReplacements mulighed for production konfiguration med posten i liste 15.

{
  "//": "angular.json",
  "projects": {
    "tiny-app": {
      "architect": {
        "build": {
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "libs/shared/environments/src/lib/environment.ts",
                  "with": "libs/shared/environments/src/lib/environment.prod.ts"
                }
              ]
            }
          }
        }
      }
    }
  }
}

Kun én ting tilbage at gøre. Vi skal opdatere importerklæringen i main.ts at bruge miljøets arbejdsområdebibliotek som vist i oversigt 16.

// main.ts
import { enableProdMode } from '@angular/core';
import { environment } from '@workspace/shared/environments';

if (environment.production) {
  enableProdMode();
}

Prøv det lokalt

Angular CLI erstatter nu environment.ts med environment.prod.ts i produktionspakken, selvom vores applikationsprojekt kun har en transitiv afhængighed af environment.ts .

Sørg for at prøve det. Tjek din browserkonsol, når du kører nx serve --open . Meddelelsen Angular is running in the development mode. Call enableProdMode() to enable the production mode. skal udskrives.

nx build --prod

npx http-server dist/apps/tiny-app -o

Når du kører en produktionspakke lokalt med kommandoerne i liste 6, bør der ikke udlæses nogen meddelelse i din browsers konsol.

Tilføj kompileringstidskonfiguration til et bibliotek

Vi kan bruge miljøbiblioteket til at konfigurere vores applikations afhængigheder, da det tillader vores miljøkonfiguration at blive brugt i kompileringstidskonfigurationsmetoder.

Normalt vil vi tilføje en miljøudbyder, som tjenester, deklarables og Angular-moduler kan injicere, men det er ikke muligt i metoder, der returnerer ModuleWithProviders<T> , for eksempel statisk forRoot metoder på vinkelmoduler.

Det samme gælder for import af Angular-moduler. Hvis vi ønsker at indlæse visse Angular-moduler i udviklingstilstand, men ikke i produktionstilstand, kunne vi ikke afhænge af en givet miljøværdi. Vi har brug for statisk adgang til en værdi, da den evalueres på kompileringstidspunktet.

Det ville være en frygtelig idé at have et arbejdsområdebibliotek med afhængighed af et applikationsprojekt. Dette ville gå imod retningen af ​​afhængigheder i en velstruktureret arkitektur og kunne føre til cykliske afhængigheder.

Tilføj og konfigurer NgRx Store

Som et use case tilføjer vi NgRx Store og dets udviklingsværktøjer ved at bruge deres ng add skemaer som set i liste 17.

nx add @ngrx/store --minimal false

nx add @ngrx/store-devtools

Vi flytter NgRx Store-konfigurationerne fra AppModule til CoreModule da dette er den foretrukne måde at konfigurere rodinjektoren på i traditionelle Angular-applikationsprojekter. CoreModule er importeret af AppModule og kan ses på liste 18.

// core.module.ts
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '@workspace/shared/environments';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
    StoreDevtoolsModule.instrument({
      logOnly: environment.production,
      maxAge: 25,
    }),
  ],
})
export class CoreModule {}

I traditionelle Angular-arbejdsområder ville dette være fint, men vi ønsker at opretholde et lille applikationsprojekt ved at minimere mængden af ​​logik, det indeholder.

Udpak et delt dataadgangsbibliotek

Vi ønsker at beholde NgRx-specifik konfiguration af rodinjektoren i et arbejdsområdebibliotek. Nx foreskriver en dataadgangsarbejdsområdebibliotekstype, så lad os generere en og udtrække konfigurationslogikken til den.

nx generate library data-access --directory=shared --tags="scope:shared,type:data-access" --style=scss

mv ./apps/tiny-app/src/app/reducers ./libs/shared/data-access/src/lib

Udfør kommandoerne i liste 19 for at generere et delt dataadgangsbibliotek og flyt undermappen src/app/reducers genereret ved tilføjelse af NgRx Store.

Naviger til libs/shared/data-access/src/lib/shared-data-access.module.ts og rediger den, så den indeholder filindholdet i liste 20.

// shared-data-access.module.ts
import { ModuleWithProviders, NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { environment } from '@workspace/shared/environments';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
    StoreDevtoolsModule.instrument({
      logOnly: environment.production,
      maxAge: 25,
    }),
  ],
})
export class SharedDataAccessRootModule {}

@NgModule({})
export class SharedDataAccessModule {
  static forRoot(): ModuleWithProviders<SharedDataAccessRootModule> {
    return {
      ngModule: SharedDataAccessRootModule,
    };
  }
}

Vi følger forRoot mønster for at angive, at de afhængigheder, der er angivet ved import af dette Angular-modul, er til rodinjektoren. Dette gøres ved at oprette en statisk metode, der returnerer en ModuleWithProviders<T> objekt.

SharedDataAccessRootModule som modulet med udbyderobjektet henviser til indeholder den konfiguration, som var i CoreModule før vi oprettede dette bibliotek.

Til sidst skal du navigere til apps/tiny-app/src/app/core.module.ts og rediger dens filindhold til det i liste 21.

// core.module.ts
import { NgModule } from '@angular/core';
import { SharedDataAccessModule } from '@workspace/shared/data-access';

@NgModule({
  imports: [
    SharedDataAccessModule.forRoot(),
  ],
})
export class CoreModule {}

Efter omstrukturering ender vi med grafen for arbejdsområdeafhængighed illustreret i figur 2.

Uden at udpakke et delt miljøbibliotek ville vi ikke have været i stand til at importere en miljøfil i vores delte dataadgangsbibliotek. Først og fremmest tiny-app har ikke en scoped stimapping. For det andet må et biblioteksprojekt aldrig afhænge af et ansøgningsprojekt.

Tilføj en meta-reducer kun i udviklingstilstand

Nu kan vi bruge miljøobjektet til at konfigurere injektorer. Den genererede NgRx Store-konfigurationskode gør dette et andet sted, nemlig i reduceringsfilen som vist i oversigt 22, hvor meta-reducere er defineret.

// reducers/index.ts
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
import { environment } from '@workspace/shared/environments';

export interface State {}

export const reducers: ActionReducerMap<State> = {};

export const metaReducers: MetaReducer<State>[] =
  !environment.production ? [] : [];

Lad os bruge en opskrift fra NgRx-dokumentationen til at tilføje en meta-reducer til kun udviklingsfejl.

// reducers/debug.ts
import { ActionReducer } from '@ngrx/store';

export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
  return (state, action) => {
    console.log('state', state);
    console.log('action', action);

    return reducer(state, action);
  };
}

Fejlfindingsmeta-reduceren i liste 23 logger NgRx Store-tilstanden og den afsendte handling, hver gang handlinger er ved at blive reduceret.

// reducers/index.ts
import { ActionReducerMap, MetaReducer } from '@ngrx/store';
import { environment } from '@workspace/shared/environments';

import { debug } from './debug';

export interface State {}

export const reducers: ActionReducerMap<State> = {};

export const metaReducers: MetaReducer<State>[] =
  !environment.production ? [debug] : [];

Liste 24 viser, hvordan man tilføjer debug-meta-reduceren kun i udviklingstilstand. Bemærk, at vi importerer miljøobjektet fra miljøbiblioteket.

// shared-data-access.module.ts
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';

import { metaReducers, reducers } from './reducers';

@NgModule({
  imports: [
    StoreModule.forRoot(reducers, {
      metaReducers,
    }),
  ],
})
export class SharedDataAccessRootModule {}

Den eksporterede metaReducers array bruges til at konfigurere rodlageret som vist i oversigt 25.

Figur 3 viser fil- og mappestrukturen for vores delte dataadgangsbibliotek, som indeholder rodlagerkonfigurationen og meta-reducere.

Konfigurer Nx-arbejdsområdeafhængigheder

Nx-arbejdsområder har en arbejdsområdekonfiguration, som kan bruges til at opsætte begrænsninger for interne afhængigheder og instruere Nx om afhængigheder, der ikke er synlige i applikations- og biblioteks TypeScript-filer.

{
  "//": "nx.json",
  "projects": {
    "tiny-app": {
      "implicitDependencies": [
        "shared-assets",
        "shared-styles"
      ]
    }
  }
}

Liste 25 viser, hvordan vi konfigurerer vores applikationsprojekt til at have implicitte afhængigheder af aktiver og stilbiblioteker. Dette er nødvendigt, da der ikke er nogen TypeScript-importsætninger, der refererer til nogen af ​​disse arbejdsrumsbiblioteker.

Miljøbiblioteket importeres i main.ts , så det har en eksplicit afhængighed, som Nx er i stand til at opfange på egen hånd.

Konfiguration af disse afhængigheder sørg for, at Nx's affected:* kommandoer opfanger ændringer foretaget i aktiv- og stilbibliotekerne.

Dette vil udløse behovet for at genopbygge applikationsprojektet, når du kører nx affected:build . Det vil også udløse applikationsenhedstests og ende-til-ende-tests til at køre med nx affected:test eller nx affected:e2e . Endelig vil den vise ændrede og berørte arbejdsområdeprojekter, når du kører nx affected:dep-graph .

Når vi foretager en ændring til _global.scss og kør nx affected:dep-graph , får vi afhængighedsgrafen vist i figur 4. Fremhævede noder (projekter) påvirkes af ændringen.

Et lillebitte Angular-applikationsprojekt

Efter omstrukturering af vores applikationsarbejdsområde er vores afhængighedsgraf en rettet acyklisk graf (almindeligvis forkortet som DAG) med afhængigheder, der peger i den rigtige retning som vist i figur 5.

End-to-end testprojektet tiny-app-e2e afhænger af applikationsprojektet, hvilket betyder, at det er påvirket af ændringer i applikationsprojektet, og dets tests skal derfor køres igen.

Ansøgningsprojektet tiny-app afhænger af og påvirkes af ændringer i de delte workpace-biblioteker shared-environments , shared-assets og shared-styles . Når et af disse biblioteker ændres, skal applikationen genopbygges, og dens testpakker skal køres igen. Et eksempel på dette blev illustreret i figur 2, hvor shared-styles blev ændret.

Intet arbejdsområdebibliotek afhænger af applikationsprojektet. Dette skal altid være tilfældet, ellers gør vi noget forkert.

Vores applikationsprojekt har meget få grunde til at ændre, da det indeholder minimal logik. Der er meget få grunde til nogensinde at røre ved ansøgningsprojektet igen.

I pull-anmodninger er det nemt at se, hvad der bliver ændret eller udvidet ved at se på mappenavnet på arbejdsområdets bibliotek, hvor filerne blev ændret, eller ved at køre nx affected:dep-graph som vi så i et tidligere kapitel.

Figur 6 viser standardfil- og mappestrukturen for en Nx-genereret Angular-applikation. Konfigurationsfiler som tsconfig.json og tslint.json er udeladt af illustrationen, da de forbliver uændrede af de teknikker, der er demonstreret i denne artikel.

I det lille app-projekt, filer i src/app undermappe er uberørt sammenlignet med standardapplikationsprojektet, bortset fra at vi tilføjede en CoreModule i core.module.ts når du opretter det delte dataadgangsbibliotek.

Som illustreret i figur 7 er alle undermapper af src er blevet flyttet undtagen src/app .

Det delte aktivers arbejdsområdebibliotek

assets mappen er blevet flyttet ud af applikationsprojektet og ind i shared-assets arbejdsområdebibliotek som vist i figur 8.

Vi oprettede de fælles aktiver mapper fonts , icons og images og vi samlede Nx-logoet som vist i src/assets/images undermappe af aktivbiblioteket.

.gitkeep filer er tomme pladsholderfiler, der placeres for at beholde mappestrukturen i Git-lageret, selv uden rigtige filer indeni. De kan slettes, når filer placeres i mapperne og sættes under versionskontrol. For eksempel ville det være fint at slette src/assets/images/.gitkeep , nu hvor vi har tilføjet nx-logo-white.svg til den samme overordnede mappe.

Faviconet er i src undermappe til et standardapplikationsprojekt. Vi flyttede også den fil til aktivbiblioteket til dens src undermappe.

Glob-mønstre i tiny-app:build arkitektmål for angular.json sikrer, at filer i aktivarbejdsområdets bibliotek er bundter under vores applikations byggeproces.

Biblioteket har ingen TypeScript-konfigurationsfiler, da det kun indeholder statiske filer.

Det delte stilarbejdsområdebibliotek

Det globale typografiark styles.scss er blevet flyttet fra applikationsprojektets src undermappe og ind i shared-styles arbejdsområdebibliotek som vist i figur 9.

styles.scss blev omdøbt til _global.scss for at konvertere den til en Sass-del. Sass-delen er placeret i src/lib undermappe til vores bibliotek med stilarter. Det importeres af indgangsstilarket index.scss i src undermappe.

Biblioteket indeholder ingen TypeScript-konfigurationsfiler, fordi det kun indeholder stylesheets og Sass-partialer.

Det delte miljøs arbejdsområdebibliotek

Miljøfilerne er blevet flyttet fra applikationsprojektets src/environments undermappe til src/lib undermappe til vores miljøarbejdsområdebibliotek som vist i figur 10.

Miljøobjektet gen-eksporteres af miljøbibliotekets indgangspunkt, også kendt som dets offentlige API, som er defineret i index.ts .

Konfigurationsfiler til TypeScript, TSLint og Jest samt arkitektmålene lint og test bevares, da arbejdsområdebiblioteket indeholder TypeScript.

Konklusion

Vi har genereret et Nx-arbejdsområde med en enkelt Angular-applikation. Selv før vi tilføjer nogen funktioner, kan vi udtrække arbejdsområdebiblioteker for at overholde Single Responsibility Princippet.

Aktivbiblioteket

Biblioteket med delte aktivers arbejdsområde indeholder statiske filer såsom webskrifttyper, ikoner og billeder. Den indeholder også favicon. Webapp-manifestet vil også blive tilføjet her.

Vi så et eksempel på at tilføje en billedfil til dette bibliotek og henvise til den fra vores applikationsprojekt. Dette fungerer selvfølgelig også fra UI-arbejdsområdebiblioteker og funktionsbiblioteker.

Med statiske filer placeret i et separat arbejdsområdebibliotek mindsker vi risikoen for at ødelægge hele applikationen, når du tilføjer, sletter eller ændrer statiske filer.

Stilbiblioteket

Med et arbejdsområdebibliotek udelukkende til globale stilarter, behøver vi ikke have det dårligt med at forurene applikationsprojektet med snesevis af Sass-partialer eller risikere at bryde applikationsopsætningen ved et uheld.

Biblioteket med delte stilarter kan også afsløre Sass-mixins, funktioner og partialer, der deles mellem komponenttypografier eller UI-arbejdsområdebiblioteker.

Miljøbiblioteket

Udpakning af miljøfilerne til et delt arbejdsområdebibliotek giver os mulighed for betinget at konfigurere injektorer fra arbejdsområdebiblioteker, såsom det delte dataadgangsbibliotek, vi oprettede for at konfigurere NgRx Store i rodinjektoren.

I en rigtig applikation kunne vi tilføje et feature shell-bibliotek, så det ville blive orkestreringsvinkelmodulet importeret af AppModule eller CoreModule .

Uden et feature shell-bibliotek er vi nødt til at foretage ændringer i applikationsprojektet for at tilføje yderligere konfiguration af rodinjektoren eller tilføje applikationstilfælde. Dette er risikabelt. Vi er bedre stillet ved at lade ansøgningsprojektet stå uberørt under de fleste omstændigheder for at få ro i sindet.

Delte arbejdsområdebiblioteker

I eksemplerne vist i denne artikel har vi lagt de udpakkede arbejdsrumsbiblioteker i shared biblioteksgrupperingsmappe og tilføjede scope:shared tag. For arbejdsområder med kun et enkelt program er dette muligvis ikke nødvendigt.

Men efterhånden som applikationen vokser, vil vi være glade for, at vi brugte grupperingsmapper fra starten af ​​projektet. Applikationsdækkende arbejdsområdebiblioteker er i shared grupperingsmappe, mens vi f.eks. bruger underdomænegrupperingsmapper til at gruppere vores funktionsbiblioteker og deres relaterede dataadgangs-, domæne- og UI-arbejdsområdebiblioteker.

Alternativt ville vi ende med dusinvis, hvis ikke hundredvis af biblioteksmapper inden for libs mappe, hver med stadig længere mappenavne.

Hvis det viste sig, at vi ønskede at tilføje yderligere applikationer til arbejdsområdet, ville vi beholde de arbejdsområdebiblioteker, som vi ønskede at dele mellem applikationerne i shared biblioteksgrupperingsmappe. Dem, som vi kunne eller ikke ønsker at dele mellem applikationerne, kan placeres i en biblioteksgrupperingsmappe opkaldt efter applikationen, for eksempel libs/tiny-app/shared for applikationsdækkende biblioteker, der er unikke for tiny-app ansøgningsprojekt.

Ressourcer

Du er velkommen til at klone LayZeeDK/nx-tiny-app-project på GitHub for at eksperimentere med den fulde løsning.

Se en videogennemgang af denne artikel af Oscar Lagatta.

Lær, hvordan du implementerer et feature shell-bibliotek i "Shell Library patterns with Nx and Monorepo Architectures" af Nacho Vázquez.

Peer reviewers

Tak Nacho Vazquez for at give mig værdifuld feedback på denne artikel og for vores mange interessante diskussioner, der fører os til fælles arkitektonisk indsigt 🙇‍♂️