Angular multi project workspace

Bij grote projecten komt het vaak voor dat een applicatie is opgezet met een oude versie van een framework. In de loop van de tijd is het framework een aantal keer geüpdatet naar de op dat moment recente versie. In de frontend gebeurt het nogal eens dat initiële keuzes niet meer in lijn zijn met de versie na update.

Van verschillende repositories naar een workspace

Bij een van de projecten waar ik onlangs aan heb gewerkt was dit ook het geval. De applicatie is opgezet met Angular 2. Daarna geüpdatet naar Angular 4 en toen ik op het project kwam heb ik de applicatie geüpdatet naar Angular 6 en een paar maanden later naar 7.
De applicatie bestaat uit een klantomgeving en een beheeromgeving. Initieel (in de tijd van Angular 2) werden deze omgevingen in 2 aparte repositories onderhouden.
Omdat er steeds meer “duplicate” code ontstond, werden beide applicaties samengevoegd en een “shared” map toegevoegd.
Op dat moment was dit een mooie oplossing die goed werkbaar was.

Angular-cli en angular.json

Echter ontstond daarmee een probleem met het creëren van componenten, services en modules met behulp van angular-cli. Angular-cli verwacht namelijk een bepaalde structuur met een root folder, zodat de gegenereerde bestanden op de juiste plek wordt geplaatst. Deze root folder staat gedefinieerd in een angular-cli.json bestand (later angular.json). De structuur na het samenvoegen van de 2 applicaties was:

Omdat in angular-cli.json maar 1 root gedefinieerd werd en gekozen is voor de klantomgeving, was het niet mogelijk om met angular-cli een component voor de beheeromgeving te genereren.

Met het volgende commando kan een component worden gegenereerd, waarbij automatisch het bijbehorende test bestand wordt gegenereerd en de component ook in de dichtstbijzijnde parent module wordt gedeclareerd.

My-component met het bijbehorende test bestand wordt nu “by default” in het volgende path geplaatst:

en my-component wordt ook gedeclareerd in de app.module.ts van klantomgeving:

Omdat my-component bedoeld was voor de beheeromgeving moesten we de bestanden handmatig verplaatsen naar de beheeromgeving en de declaratie in app.module verwijderen en toevoegen aan app.module in de beheeromgeving. Niet ideaal!

Projecten in Angular 6

Sinds Angular 6 is het mogelijk om meerdere “projecten” in 1 “workspace” op te zetten.

Hiermee worden 2 projecten aangemaakt van het type “application”

Hiermee wordt een project aangemaakt van het type “library”
De structuur van de workspace ziet er nu als volgt uit:

Voordelen van multiproject workspace

In het angular.json bestand kan nu voor elke project een root folder worden gedefinieerd. Angular-cli kan nu een component, module, service of directive genereren voor een specifiek project;

Bij het starten van de tests draaiden voorheen de tests voor zowel de beheeromgeving als de klantomgeving als de gedeelde code. Bij de huidige opzet met verschillende projecten kunnen tests onafhankelijk en tegelijkertijd voor de verschillende projecten worden gedraaid. Voordeel is dus dat de tests voor de beheeromgeving en de gedeelde omgeving nu niet meer hoeven te lopen bij ontwikkeling aan de klantomgeving. Wachten op groen duurt nu dus een derde van de tijd die het voorheen duurde. Dit principe geldt voor ook voor het bouwen. Als er geen wijzigingen zijn, hoeft ook niet opnieuw gebouwd te worden. M.a.w. er is nu weer de onafhankelijkheid van de initiële losse repositories bereikt, maar dan binnen 1 workspace in 1 repository.

Applicaties en libraries

Een library wordt gebruikt door een applicatie. Het shared project is een lib en de beheeromgeving en klantomgeving zijn applicaties. Om de gedeelde code te kunnen gebruiken moet shared gepackaged worden, zodat deze als een node_module kan worden geïmporteerd door de applicaties.

Er is nu een .tgz bestand gemaakt die net als bij het installeren van een node_module met npm kan worden geïnstalleerd in de node_modules map

De –save flag (niet meer nodig bij Angular 7) zorgt ervoor dat de library wordt toegevoegd aan de dependencies array van package.json. Dat is o.a. nodig voor de IDE om de shared code te kunnen vinden bij gebruik van import. Naast package.json is ook een public_api.ts bestand nodig waar de code wordt geëxporteerd. Public_api.ts en package.json samen zorgen ervoor dat een dependency in een applicatie geresolved kan worden.

Probleem bij gebruik in bouwstraat

Het installeren van node_modules gaat prima voor externe libs, maar gaat niet zonder problemen bij libraries binnen de huidige workspace.

Tot dusver is alles een kwestie van documentatie lezen, tutorials volgen en gebruik maken van angular-cli. Maar deze opzet in een bouwstraat geeft een aantal problemen waar ik geen forums, best practices of andere documentatie over kon vinden;

een bouwstraat maakt eerst de omgeving leeg, installeert dan de node_modules en bouwt vervolgens de applicatie.

Echter hebben we nu te maken met de shared library. Deze staat wel in package.json, maar op een lege omgeving bestaat de dist/shared nog niet. Deze moet eerst gebouwd worden, maar dat kan pas als angular-cli is geïnstalleerd met npm install. Dit klinkt als een kip en ei verhaal.

Oplossing voor bouwstraat door volgorde buildscript

Ik heb dat opgelost door eerst angular-cli te installeren, daarna de shared lib te bouwen, te packagen en te installeren. Pas dan installeer ik met npm install de nog niet geinstalleerde packages en daarna kunnen pas de beheeromgeving en  klantomgeving worden gebouwd.

Het build script ziet er nu zo uit:

In eerste instantie had ik gekozen de shared lib uit de dependencies te verwijderen, zodat deze niet wordt geïnstalleerd tijdens npm install. Op die manier hoefde ik hem alleen maar met de hand te bouwen, packagen en installeren zonder –save flag. Maar als de dependecy niet in package.json voorkomt, kan een IDE de exports van de lib bij het importeren in een component niet resolven.

Wennen en uitzoekwerk, maar het loont

Het is wennen en de setup kost uitzoekwerk, maar uiteindelijk heb je dan ook een workspace met verschillende applicaties en libraries die duidelijk gescheiden zijn gestructureerd en onafhankelijk van elkaar kunnen worden ontwikkeld, getest en gebouwd. Daarnaast is het gebruik van angular-cli bijna onmisbaar geworden bij het aanmaken van componenten, directives, modules, pipes en services. Dankzij deze opzet kan angular-cli worden gebruikt met de –project flag

Reacties

  • Interessant dit!

    Handig om te weten wellicht is wanneer je een component/service/whatever wilt generen binnen een bepaald project: ng g c my-component --project=beheeromgeving

    Kun je in de plaats hiervan ook gewoon met je terminal naar het desbetreffende project gaan en het component zonder --prefix=beheeromgeving toe te voegen.

    Bijvoorbeeld: cd beheeromgeving && ng g c my-component

    Dit werkt ook wanneer je meerdere modules gebruikt binnen je project. De CLI zal dan dus rekening houden binnen welke module je een component aan het genereren bent.

Het e-mailadres wordt niet gepubliceerd.

*