Erstellen Sie ein Monorepository mit Lernbereichen fĂŒr Herna und Garn

lernen und garn

In den letzten Jahren hat sich das Konzept der Mono-Repositories erfolgreich etabliert, da es den Prozess der Entwicklung modularer Softwareprojekte wie mikroservicebasierter Infrastrukturen erheblich vereinfachen kann. Die Hauptvorteile dieses architektonischen Ansatzes liegen in der Praxis auf der Hand. Daher schlage ich vor, ein eigenes Test- Mono-Repository von Grund auf neu zu erstellen und gleichzeitig die Nuancen der Arbeit mit Garnarbeitsbereichen und Herna zu verstehen . Nun, fangen wir an!

Betrachten Sie die Struktur unseres Projekts, bei der es sich um drei Bibliotheken im Ordner packages / sowie in package.json im Stammverzeichnis handelt.

├── package.json └── packages ├── app │  ├── index.js │  └── package.json ├── first │  ├── index.js │  └── package.json └── second ├── index.js └── package.json 

Es versteht sich, dass wir zuerst zwei und zwei unabhÀngige Bibliotheken sowie eine App- Bibliothek haben, die Funktionen aus den ersten beiden importiert. Der Einfachheit halber werden alle drei Pakete im Paketverzeichnis abgelegt. Sie können sie im Stammordner belassen oder in einem Verzeichnis mit einem anderen Namen ablegen. Um jedoch den allgemein anerkannten Konventionen zu folgen, werden sie auf diese Weise abgelegt.

Die Bibliotheken 1 und 2 enthalten zur Vereinfachung des Experiments nur eine Funktion in index.js , von denen jede im Namen des Moduls eine Hallo-Zeichenfolge zurĂŒckgibt . FĂŒr das erste Beispiel sieht es so aus:

 // packages/first/index.js const first = () => 'Hi from the first module'; module.exports = first; 

Im App- Modul zeigen wir die Meldung Hallo von der App in der Konsole sowie GrĂŒĂŸe von zwei anderen Paketen an:

 // packages/app/index.js const first = require('@monorepo/first'); const second = require('@monorepo/second'); const app = () => 'Hi from the app'; const main = () => { console.log(app()); console.log(first()); console.log(second()); }; main(); module.exports = { app, main }; 

Damit erstens und zweitens in der App verfĂŒgbar sind , bezeichnen wir sie als AbhĂ€ngigkeiten in AbhĂ€ngigkeiten .

FĂŒgen Sie außerdem fĂŒr jede Bibliothek das PrĂ€fix @ monorepo / im Wert von name zum Paketnamen vor dem Hauptpaketnamen in der lokalen package.json hinzu .

 // packages/app/package.json { "name": "@monorepo/app", "version": "1.0.0", "main": "index.js", "license": "MIT", "dependencies": { "@monorepo/first": "^1.0.0", "@monorepo/second": "^1.0.0" } } 

Warum brauche ich ein PrÀfix mit einem Hundesymbol vor dem Paketnamen npm (@ monorepo /)?
Das HinzufĂŒgen eines PrĂ€fixes ist optional, aber dies ist genau die Konvention der Paketbenennung, an die sich viele Monorepositorys halten: babel ,
Material UI , eckig und andere. Tatsache ist, dass jeder Benutzer oder jede Organisation seinen eigenen Bereich auf der npm- Website hat. Daher besteht die Garantie, dass alle Module mit dem @ somescope / postfix vom somescope- Team und nicht von Angreifern erstellt werden. DarĂŒber hinaus können bereits vergebene Modulnamen aufgerufen werden. Sie können beispielsweise nicht einfach Ihr eigenes Utils- Modul erstellen, da eine solche Bibliothek bereits vorhanden ist . Wenn Sie jedoch das Postfix @ myscopename / hinzufĂŒgen , können Sie unsere Utils ( @ myscopename / utils ) mit Blackjack und jungen Damen erhalten.

Ein Analogon aus dem wirklichen Leben fĂŒr unser Testprojekt können verschiedene Bibliotheken fĂŒr die Arbeit mit Daten, Validierungswerkzeugen, Analysen oder nur eine Reihe von UI-Komponenten sein. Wenn wir davon ausgehen, dass wir eine Web- und eine mobile Anwendung entwickeln werden (z. B. mit React bzw. React Native ) und einen Teil der wiederverwendeten Logik haben, kann es sich lohnen, sie fĂŒr die spĂ€tere Verwendung in anderen Projekten in separate Komponenten zu integrieren. FĂŒgen Sie dazu den Server auf Node.js hinzu und Sie erhalten einen sehr realen Fall aus dem Leben.

Garnarbeitsbereiche


Der letzte Schliff vor dem Erstellen eines vollwertigen Mono-Repositorys ist das Design von package.json im Stammverzeichnis unseres Repositorys. Beachten Sie die Eigenschaft workspaces - wir haben den Wert von packages / * angegeben , was "alle UnterschlĂŒssel im Paketordner" bedeutet. In unserem Fall ist dies die erste und zweite App .

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ] } 

Außerdem muss in package.json "private": true angegeben werden , da Arbeitsbereiche nur in privaten Projekten verfĂŒgbar sind.

FĂŒhren Sie den Befehl yarn (analog zu yarn install oder npm install ) aus dem Stammverzeichnis aus, damit alles abheben kann. Da die im App- Modul vorhandenen AbhĂ€ngigkeiten im Stammpaket.json als Arbeitsbereiche definiert sind, werden wir nichts von der npm-Registrierung herunterladen, sondern einfach unsere Pakete binden ("verlinken").

 yarn 

Bild

Jetzt können wir den Knotenbefehl ausfĂŒhren . aus dem Stammverzeichnis, in dem das Skript aus der Datei packages / app / index.js ausgefĂŒhrt wird .

 node . 

Bild

Mal sehen, wie es funktioniert. Durch Aufrufen von Garn haben wir in node_modules symbolische Links zu unseren Verzeichnissen im Paketordner erstellt .

Bild

Aufgrund dieser AbhĂ€ngigkeitsbeziehung haben wir einen großen Vorteil: Wenn wir jetzt das erste und zweite Modul Ă€ndern, erhĂ€lt unsere App die aktuelle Version dieser Pakete, ohne sie neu zu erstellen. In der Praxis ist es sehr praktisch, weil Wir können Pakete lokal entwickeln und sie dennoch als AbhĂ€ngigkeiten von Drittanbietern definieren (zu denen sie schließlich werden).

Der nÀchste wichtige Vorteil, den Sie durch die Arbeit mit Garnarbeitsbereichen erzielen können, ist die Organisation der Speicherung von AbhÀngigkeiten von Drittanbietern.

Weitere Informationen zum Speichern von AbhÀngigkeiten auf oberster Ebene.
Angenommen, wir wollten die Lodash- Bibliothek in der ersten und zweiten verwenden . Durch AusfĂŒhren des Befehls yarn add lodash aus den entsprechenden Verzeichnissen erhalten wir eine Aktualisierung der lokalen package.json - die aktuelle Version des Pakets wird in AbhĂ€ngigkeiten angezeigt .
 "dependencies": { "lodash": "^4.17.11" } 

Was das lodash- Paket selbst betrifft - physisch wird die Bibliothek einmal in node_modules auf der Stammebene installiert.
Wenn die erforderliche Version des externen Pakets (in unserem Fall lodash ) fĂŒr first und second unterschiedlich ist (z. B. benötigen Sie zuerst lodash v3.0.0 und in second v4.0.0 ), gelangt ein Paket mit einer niedrigeren Version ( 3.0.0 ) zu den root node_modules , und die lodash- Version fĂŒr das zweite Modul wird in den lokalen Paketen / second / node_modules gespeichert .
ZusĂ€tzlich zu den Vorteilen kann dieser Ansatz geringfĂŒgige Nachteile aufweisen, die das Garn mit Hilfe zusĂ€tzlicher Fahnen umgehen kann. Weitere Informationen zu solchen Nuancen finden Sie in der offiziellen Dokumentation .

Lerna hinzufĂŒgen


Der erste Schritt bei der Arbeit mit lerna ist die Installation des Pakets. Normalerweise fĂŒhren sie eine globale Installation durch ( Garn global add lerna oder npm i -g lerna ). Wenn Sie jedoch nicht sicher sind, ob Sie diese Bibliothek verwenden möchten, können Sie den Aufruf mit npx verwenden .

Wir werden lerna aus dem Stammverzeichnis initialisieren:

 lerna init 

Bild

TatsĂ€chlich haben wir mit Hilfe eines Befehls mehrere Aktionen gleichzeitig ausgefĂŒhrt: ein Git-Repository erstellt (falls es zuvor nicht initialisiert worden war), eine lerna.json- Datei erstellt und unser Stammpaket.json aktualisiert.

FĂŒgen Sie nun in der neu erstellten Datei lerna.json zwei Zeilen hinzu - "npmClient": "Garn" und "useWorkspaces": true . In der letzten Zeile steht, dass wir bereits Garnarbeitsbereiche verwenden und der Ordner app / node_modules mit symbolischen Links zum ersten und zweiten nicht erstellt werden muss .

 // lerna.json { "npmClient": "yarn", "packages": [ "packages/*" ], "version": "1.0.0", "useWorkspaces": true } 

Tests mit Lerna


Um die Bequemlichkeit der Arbeit mit lerna zu demonstrieren, fĂŒgen Sie Tests fĂŒr unsere Bibliotheken hinzu.
Aus dem Stammverzeichnis installieren wir das Paket zum Testen - Scherz . FĂŒhren Sie den folgenden Befehl aus:

 yarn add -DW jest 

Warum brauche ich das Flag -DW?
Das Flag -D (- dev) wird benötigt, damit das Scherzpaket als Dev-AbhÀngigkeit installiert wird, und das Flag -W (- ignore-workspace-root-check) ermöglicht die Installation auf der Root-Ebene (die wir benötigen).

Der nĂ€chste Schritt ist das HinzufĂŒgen einer Testdatei zu unserem Paket. Zur Vereinfachung unseres Beispiels werden wir alle Tests Ă€hnlich machen. Im ersten Beispiel sieht die Testdatei folgendermaßen aus:

 // packages/first/test.js const first = require('.'); describe('first', () => { it('should return correct message', () => { const result = first(); expect(result).toBe('Hi from the first module'); }); }); 

Wir mĂŒssen auch ein Skript hinzufĂŒgen, um Tests in package.json jeder unserer Bibliotheken auszufĂŒhren :

 // packages/*/package.json ... "scripts": { "test": "../../node_modules/.bin/jest --colors" }, ... 

Der letzte Schliff wird die Aktualisierung der root package.json sein . FĂŒgen Sie ein Testskript hinzu , das lerna run test --stream aufruft . Der Parameter nach lerna run definiert den Befehl, der in jedem unserer Pakete aus dem Paket / Ordner aufgerufen wird, und das Flag --stream ermöglicht es uns, die Ausgabe der Ergebnisse im Terminal anzuzeigen .

Infolgedessen sieht package.json aus dem Stammverzeichnis folgendermaßen aus:

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } } 

Um die Tests auszufĂŒhren, mĂŒssen wir nur den Befehl vom Stammverzeichnis unseres Projekts aus ausfĂŒhren:

 yarn test 

Bild

Versions-Upgrade mit Lerna


Die nĂ€chste beliebte Aufgabe, mit der lerna die QualitĂ€t bewĂ€ltigen kann, ist die Aktualisierung der Paketversionen. Stellen Sie sich vor, wir haben uns nach der Implementierung der Tests entschlossen, unsere Bibliotheken von 1.0.0 auf 2.0.0 zu aktualisieren. FĂŒgen Sie dazu einfach die Zeile "update: version": "lerna version --no-push" in das Skriptfeld der Datei " root package.json" ein und fĂŒhren Sie dann " Garn update: version" aus dem Stammverzeichnis aus. Das Flag --no-push wird hinzugefĂŒgt, damit die Änderungen nach dem Aktualisieren der Version nicht an das Remote-Repository gesendet werden, was lerna standardmĂ€ĂŸig tut (ohne dieses Flag).

Infolgedessen sieht unser root package.json folgendermaßen aus:

 // package.json { "name": "monorepo", "version": "1.0.0", "main": "packages/app/index.js", "license": "MIT", "private": true, "workspaces": [ "packages/*" ], "scripts": { "test": "lerna run test --stream", "update:version": "lerna version --no-push" }, "devDependencies": { "jest": "^24.7.1", "lerna": "^3.13.2" } } 

FĂŒhren Sie das Versionsaktualisierungsskript aus:

 yarn update:version 

Als nÀchstes werden wir aufgefordert, die Version auszuwÀhlen, zu der wir wechseln möchten:

Bild

Durch Klicken auf die Eingabetaste erhalten wir eine Liste der Pakete, in denen die Version aktualisiert wird.

Bild

Wir bestĂ€tigen das Update durch Eingabe von y und erhalten eine Nachricht ĂŒber das erfolgreiche Update.

Bild

Wenn wir versuchen, den Befehl git status auszufĂŒhren, erhalten wir die Nachricht, dass nichts festgeschrieben werden muss Die lerna-Version aktualisiert nicht nur die Paketversionen, sondern erstellt auch ein Git-Commit und ein Tag, das die neue Version angibt (in unserem Fall v2.0.0).

Funktionen der Arbeit mit dem lerna version team
Wenn Sie im Skriptfeld der Datei root package.json die Zeile "version": "lerna version --no-push" anstelle von "update: version": "lerna version --no-push" hinzufĂŒgen , können Sie höchstwahrscheinlich auf unerwartetes Verhalten stoßen rote Konsole. Tatsache ist, dass npm-scripts standardmĂ€ĂŸig den Versionsbefehl (reserviertes Skript) unmittelbar nach dem Aktualisieren der Paketversion aufruft , was zu einem rekursiven Aufruf der lerna-Version fĂŒhrt . Um diese Situation zu vermeiden, reicht es aus, dem Skript einen anderen Namen zu geben, z. B. update: version , wie in unserem Beispiel.

Fazit


Diese Beispiele zeigen ein Hundertstel aller Möglichkeiten, die lerna in Verbindung mit Garnarbeitsbereichen bietet. Leider habe ich bisher keine detaillierten Anweisungen fĂŒr die Arbeit mit Monorepositories auf Russisch gefunden, sodass wir davon ausgehen können, dass der Anfang gemacht wurde!

Link zum Testprojekt-Repository.

Source: https://habr.com/ru/post/de448766/


All Articles