Ich arbeite seit mehreren Jahren am selben Projekt. Seine ursprüngliche Version war eine riesige monolithische Anwendung mit Tausenden von Dateien. Sie war schlecht architektonisch und nicht wiederverwendbar, aber sie wurde in einem einzigen Repository gehostet, was die Arbeit damit erleichterte. Später habe ich das Chaos im Projekt "behoben", indem ich die Codebasis in autonome Pakete aufgeteilt, jedes davon in einem eigenen Repository gehostet und sie mit Composer verwaltet habe. Die Codebasis wurde ordnungsgemäß architektonisch und wiederverwendbar, aber die Aufteilung auf mehrere Repositories machte die Arbeit damit wesentlich schwieriger.
Da der Code immer wieder neu formatiert wurde, musste sich auch sein Hosting im Repository anpassen, von dem anfänglichen einzelnen Repository über mehrere Repositories zu einem Monorepo bis hin zu dem, was man als "Multi-Monorepo" bezeichnen könnte.
Ich nehme Sie mit auf die Reise, wie dies geschah, und erkläre, warum und wann ich das Gefühl hatte, zu einem neuen Ansatz wechseln zu müssen. Die Reise besteht aus vier (bisherigen!) Etappen, also lassen Sie sie uns so aufteilen.
Etappe 1: Einzelnes Repository
Das Projekt ist leoloso/PoP und hat mehrere Hosting-Schemata durchlaufen, entsprechend der Neugestaltung seines Codes zu verschiedenen Zeiten.
Es wurde als diese WordPress-Seite geboren und umfasste ein Theme und mehrere Plugins. Der gesamte Code wurde im selben Repository zusammen gehostet.
Einige Zeit später benötigte ich eine weitere Website mit ähnlichen Funktionen, also ging ich den schnellen und einfachen Weg: Ich duplizierte das Theme und fügte eigene benutzerdefinierte Plugins hinzu, alles im selben Repository. Ich bekam die neue Website im Handumdrehen zum Laufen.
Das Gleiche tat ich für eine weitere Website, dann für eine weitere, und noch eine. Schließlich beherbergte das Repository etwa 10 Websites mit Tausenden von Dateien.

Probleme mit dem einzelnen Repository
Während dieses Setup die einfache Erstellung neuer Websites ermöglichte, skalierte es überhaupt nicht gut. Das Wichtigste ist, dass eine einzelne Änderung das Suchen nach demselben String über alle 10 Websites hinweg beinhaltete. Das war völlig unüberschaubar. Sagen wir einfach, Kopieren/Einfügen/Suchen/Ersetzen wurde für mich zur Routine.
Es war also an der Zeit, mit PHP den richtigen Weg zu gehen.
Etappe 2: Multi-Repository
Schneller Vorlauf zwei Jahre. Ich habe die Anwendung vollständig in PHP-Pakete aufgeteilt, die über Composer und Dependency Injection verwaltet werden.
Composer verwendet Packagist als sein Haupt-PHP-Paket-Repository. Um ein Paket zu veröffentlichen, benötigt Packagist eine composer.json-Datei am Stammverzeichnis des Repositorys des Pakets. Das bedeutet, dass wir nicht mehrere PHP-Pakete haben können, von denen jedes seine eigene composer.json im selben Repository hostet.
Folglich musste ich vom Hosten des gesamten Codes im einzelnen leoloso/PoP-Repository auf die Verwendung mehrerer Repositories umsteigen, mit einem Repository pro PHP-Paket. Um sie zu verwalten, erstellte ich die Organisation "PoP" auf GitHub und hostete dort alle Repositories, einschließlich getpop/root, getpop/component-model, getpop/engine und viele andere.

Probleme mit dem Multi-Repository
Die Verwaltung eines Multi-Repositorys kann einfach sein, wenn Sie eine Handvoll PHP-Pakete haben. Aber in meinem Fall umfasste die Codebasis über 200 PHP-Pakete. Ihre Verwaltung war kein Vergnügen.
Der Grund dafür, dass das Projekt in so viele Pakete aufgeteilt wurde, ist, dass ich den Code auch von WordPress entkoppelt habe (damit diese auch mit anderen CMSs verwendet werden könnten), weshalb jedes Paket sehr granular sein muss und sich mit einem einzigen Ziel befasst.
Nun, 200 Pakete sind nicht gewöhnlich. Aber selbst wenn ein Projekt nur 10 Pakete umfasst, kann es schwierig sein, diese über 10 Repositories hinweg zu verwalten. Das liegt daran, dass jedes Paket versioniert werden muss und jede Version eines Pakets von einer bestimmten Version eines anderen Pakets abhängt. Beim Erstellen von Pull-Requests müssen wir die composer.json-Datei jedes Pakets so konfigurieren, dass sie den entsprechenden Entwicklungszweig seiner Abhängigkeiten verwendet. Das ist umständlich und bürokratisch.
Ich habe es schließlich vermieden, Feature-Branches überhaupt zu verwenden, zumindest in meinem Fall, und habe einfach jedes Paket auf die dev-master-Version seiner Abhängigkeiten verweisen lassen (d.h. ich habe Pakete nicht versioniert). Es würde mich nicht überraschen zu erfahren, dass dies eine gängige Praxis ist, eher häufig als nicht.
Es gibt Werkzeuge, die bei der Verwaltung mehrerer Repositories helfen, wie z. B. meta. Es erstellt ein Projekt, das aus mehreren Repositories besteht, und git commit -m "einige Nachricht" im Projekt führt einen Befehl git commit -m "einige Nachricht" in jedem Repository aus, sodass sie synchron zueinander gehalten werden können.
Meta hilft jedoch nicht bei der Verwaltung der Versionierung jeder Abhängigkeit in ihrer composer.json-Datei. Obwohl es hilft, den Schmerz zu lindern, ist es keine endgültige Lösung.
Also war es an der Zeit, alle Pakete in dasselbe Repository zu bringen.
Etappe 3: Monorepo
Das Monorepo ist ein einziges Repository, das den Code für mehrere Projekte hostet. Da es verschiedene Pakete zusammen hostet, können wir sie auch gemeinsam versionieren. Auf diese Weise können alle Pakete mit derselben Version veröffentlicht und über Abhängigkeiten verknüpft werden. Dies macht Pull-Requests sehr einfach.

Wie ich bereits erwähnt habe, können wir PHP-Pakete nicht auf Packagist veröffentlichen, wenn sie im selben Repository gehostet werden. Aber wir können diese Einschränkung überwinden, indem wir Entwicklung und Verteilung des Codes entkoppeln: Wir verwenden das Monorepo, um den Quellcode zu hosten und zu bearbeiten, und mehrere Repositories (ein Repository pro Paket), um sie zur Verteilung und zum Konsum auf Packagist zu veröffentlichen.

Umstieg auf das Monorepo
Der Wechsel zum Monorepo-Ansatz umfasste die folgenden Schritte
Zuerst habe ich die Ordnerstruktur in leoloso/PoP erstellt, um die verschiedenen Projekte zu beherbergen. Ich entschied mich für eine zweistufige Hierarchie, zuerst unter layers/, um das breitere Projekt anzudeuten, und dann unter packages/, plugins/, clients/ und anderes, um die Kategorie anzudeuten.

Dann kopierte ich den gesamten Quellcode aus allen Repositories (getpop/engine, getpop/component-model, etc.) an den entsprechenden Ort für dieses Paket im Monorepo (d.h. layers/Engine/packages/engine, layers/Engine/packages/component-model, etc).
Ich brauchte die Git-Historie der Pakete nicht zu behalten, also kopierte ich die Dateien einfach mit Finder. Andernfalls können wir hraban/tomono oder shopsys/monorepo-tools verwenden, um Repos in das Monorepo zu portieren und dabei ihre Git-Historie und Commit-Hashes zu erhalten.
Als Nächstes aktualisierte ich die Beschreibung aller nachgelagerten Repositories, beginnend mit [READ ONLY], wie z. B. dieses hier.

Ich habe diese Aufgabe in Stapeln über die GraphQL-API von GitHub ausgeführt. Zuerst habe ich alle Beschreibungen aus allen Repositories mit dieser Abfrage abgerufen
{
repositoryOwner(login: "getpop") {
repositories(first: 100) {
nodes {
id
name
description
}
}
}
}
...was eine Liste wie diese zurückgab
{
"data": {
"repositoryOwner": {
"repositories": {
"nodes": [
{
"id": "MDEwOlJlcG9zaXRvcnkxODQ2OTYyODc=",
"name": "hooks",
"description": "Contracts to implement hooks (filters and actions) for PoP"
},
{
"id": "MDEwOlJlcG9zaXRvcnkxODU1NTQ4MDE=",
"name": "root",
"description": "Declaration of dependencies shared by all PoP components"
},
{
"id": "MDEwOlJlcG9zaXRvcnkxODYyMjczNTk=",
"name": "engine",
"description": "Engine for PoP"
}
]
}
}
}
}
Von dort kopierte ich alle Beschreibungen, fügte [READ ONLY] hinzu und generierte für jedes Repository eine neue Abfrage, die die GraphQL-Mutation updateRepository ausführt
mutation {
updateRepository(
input: {
repositoryId: "MDEwOlJlcG9zaXRvcnkxODYyMjczNTk="
description: "[READ ONLY] Engine for PoP"
}
) {
repository {
description
}
}
}
Schließlich führte ich Werkzeuge ein, die beim "Aufteilen des Monorepos" helfen. Die Verwendung eines Monorepos beruht auf der Synchronisierung des Codes zwischen dem vorgelagerten Monorepo und den nachgelagerten Repositories, ausgelöst jedes Mal, wenn ein Pull-Request zusammengeführt wird. Diese Aktion wird als "Aufteilen des Monorepos" bezeichnet. Das Aufteilen des Monorepos kann mit einem git subtree split-Befehl erreicht werden, aber da ich faul bin, verwende ich lieber ein Werkzeug.
Ich wählte Monorepo builder, der in PHP geschrieben ist. Dieses Werkzeug gefällt mir, weil ich es mit eigener Funktionalität anpassen kann. Andere beliebte Werkzeuge sind der Git Subtree Splitter (in Go geschrieben) und Git Subsplit (Bash-Skript).
Was mir am Monorepo gefällt
Mit dem Monorepo fühle ich mich wohl. Die Entwicklungsgeschwindigkeit hat sich verbessert, da die Arbeit mit 200 Paketen sich ziemlich wie die Arbeit mit nur einem anfühlt. Der Schub ist am deutlichsten beim Refactoring der Codebasis, d. h. bei der Durchführung von Aktualisierungen über viele Pakete hinweg.
Das Monorepo ermöglicht es mir auch, mehrere WordPress-Plugins gleichzeitig zu veröffentlichen. Alles, was ich tun muss, ist, GitHub Actions über PHP-Code (bei Verwendung des Monorepo-Builders) eine Konfiguration bereitzustellen, anstatt sie fest in YAML zu codieren.
Um ein WordPress-Plugin zur Verteilung zu generieren, hatte ich einen generate_plugins.yml Workflow erstellt, der beim Erstellen einer Veröffentlichung ausgelöst wird. Mit dem Monorepo habe ich ihn angepasst, um nicht nur ein, sondern mehrere Plugins zu generieren, die über PHP über einen benutzerdefinierten Befehl in plugin-config-entries-json konfiguriert und wie hier in GitHub Actions aufgerufen werden.
- id: output_data
run: |
echo "quot;::set-output name=plugin_config_entries::$(vendor/bin/monorepo-builder plugin-config-entries-json)"
Auf diese Weise kann ich mein GraphQL API-Plugin und andere im Monorepo gehostete Plugins auf einmal generieren. Die über PHP definierte Konfiguration ist diese hier.
class PluginDataSource
{
public function getPluginConfigEntries(): array
{
return [
// GraphQL API for WordPress
[
'path' => 'layers/GraphQLAPIForWP/plugins/graphql-api-for-wp',
'zip_file' => 'graphql-api.zip',
'main_file' => 'graphql-api.php',
'dist_repo_organization' => 'GraphQLAPI',
'dist_repo_name' => 'graphql-api-for-wp-dist',
],
// GraphQL API - Extension Demo
[
'path' => 'layers/GraphQLAPIForWP/plugins/extension-demo',
'zip_file' => 'graphql-api-extension-demo.zip',
'main_file' =>; 'graphql-api-extension-demo.php',
'dist_repo_organization' => 'GraphQLAPI',
'dist_repo_name' => 'extension-demo-dist',
],
];
}
}
Beim Erstellen einer Veröffentlichung werden die Plugins über GitHub Actions generiert.

Wenn ich in Zukunft den Code für ein weiteres Plugin zum Repository hinzufüge, wird es auch ohne Probleme generiert. Zeit und Energie in dieses Setup zu investieren, spart zukünftig definitiv viel Zeit und Energie.
Probleme mit dem Monorepo
Ich glaube, dass das Monorepo besonders nützlich ist, wenn alle Pakete in derselben Programmiersprache kodiert sind, eng gekoppelt sind und dasselbe Tooling verwenden. Wenn wir stattdessen mehrere Projekte haben, die auf verschiedenen Programmiersprachen basieren (wie JavaScript und PHP), aus nicht zusammenhängenden Teilen bestehen (wie der Code der Hauptwebsite und eine Subdomain, die das Abonnieren von Newslettern verwaltet) oder unterschiedliches Tooling verwenden (wie PHPUnit und Jest), dann glaube ich nicht, dass das Monorepo einen großen Vorteil bietet.
Dennoch gibt es Nachteile beim Monorepo
- Wir müssen für den gesamten im Monorepo gehosteten Code dieselbe Lizenz verwenden. Andernfalls können wir keine
LICENSE.md-Datei am Stammverzeichnis des Monorepos hinzufügen, damit GitHub sie automatisch erkennt. Tatsächlich stellteleoloso/PoPanfangs mehrere Bibliotheken unter MIT und das Plugin unter GPLv2 zur Verfügung. Also entschied ich mich, es unter Verwendung des kleinsten gemeinsamen Nenners zwischen ihnen zu vereinfachen, was GPLv2 ist. - Es gibt viel Code, viel Dokumentation und viele Issues, alles von verschiedenen Projekten. Daher können potenzielle Mitwirkende, die von einem bestimmten Projekt angezogen wurden, leicht verwirrt werden.
- Beim Taggen des Codes werden alle Pakete unabhängig mit diesem Tag versioniert, unabhängig davon, ob ihr spezifischer Code aktualisiert wurde oder nicht. Dies ist ein Problem mit dem Monorepo-Builder und nicht unbedingt mit dem Monorepo-Ansatz (Symfony hat dieses Problem gelöst für sein Monorepo).
- Das Issues-Board benötigt ordnungsgemäße Verwaltung. Insbesondere erfordert es Labels, um Issues dem entsprechenden Projekt zuzuweisen, oder es droht, chaotisch zu werden.

All diese Probleme sind jedoch keine Hindernisse. Ich kann damit umgehen. Es gibt jedoch ein Problem, das das Monorepo nicht lösen kann: das gemeinsame Hosten von öffentlichem und privatem Code.
Ich plane, eine "PRO"-Version meines Plugins zu erstellen, die ich in einem privaten Repository hosten möchte. Der Code im Repository ist jedoch entweder öffentlich oder privat, sodass ich meinen privaten Code nicht im öffentlichen leoloso/PoP-Repository hosten kann. Gleichzeitig möchte ich mein Setup auch für das private Repository beibehalten, insbesondere den generate_plugins.yml-Workflow (der das Plugin bereits scoptet und seinen Code von PHP 8.0 auf 7.1 herabstuft) und seine Möglichkeit, ihn über PHP zu konfigurieren. Und ich möchte es DRY halten, indem ich Copy/Paste vermeide.
Es war an der Zeit, zum Multi-Monorepo zu wechseln.
Etappe 4: Multi-Monorepo
Der Multi-Monorepo-Ansatz besteht darin, dass verschiedene Monorepos ihre Dateien miteinander teilen, verknüpft über Git-Submodule. Ganz grundlegend besteht ein Multi-Monorepo aus zwei Monorepos: einem autonomen vorgelagerten Monorepo und einem nachgelagerten Monorepo, das das vorgelagerte Repo als Git-Submodul einbettet, das in der Lage ist, auf seine Dateien zuzugreifen.

Dieser Ansatz erfüllt meine Anforderungen durch
- das öffentliche Repository
leoloso/PoPals vorgelagertes Monorepo und - die Erstellung eines privaten Repositories
leoloso/GraphQLAPI-PRO, das als nachgelagertes Monorepo dient.

leoloso/GraphQLAPI-PRO bettet leoloso/PoP im Unterordner submodules/PoP ein (beachten Sie, wie GitHub auf den spezifischen Commit des eingebetteten Repos verlinkt)

Nun kann leoloso/GraphQLAPI-PRO auf alle Dateien von leoloso/PoP zugreifen. Zum Beispiel kann das Skript ci/downgrade/downgrade_code.sh aus leoloso/PoP (das den Code von PHP 8.0 auf 7.1 herabstuft) unter submodules/PoP/ci/downgrade/downgrade_code.sh aufgerufen werden.
Zusätzlich kann das nachgelagerte Repository den PHP-Code aus dem vorgelagerten Repository laden und sogar erweitern. Auf diese Weise kann die Konfiguration zur Generierung der öffentlichen WordPress-Plugins überschrieben werden, um stattdessen die PRO-Plugin-Versionen zu erstellen.
class PluginDataSource extends UpstreamPluginDataSource
{
public function getPluginConfigEntries(): array
{
return [
// GraphQL API PRO
[
'path' => 'layers/GraphQLAPIForWP/plugins/graphql-api-pro',
'zip_file' => 'graphql-api-pro.zip',
'main_file' => 'graphql-api-pro.php',
'dist_repo_organization' => 'GraphQLAPI-PRO',
'dist_repo_name' => 'graphql-api-pro-dist',
],
// GraphQL API Extensions
// Google Translate
[
'path' => 'layers/GraphQLAPIForWP/plugins/google-translate',
'zip_file' => 'graphql-api-google-translate.zip',
'main_file' => 'graphql-api-google-translate.php',
'dist_repo_organization' => 'GraphQLAPI-PRO',
'dist_repo_name' => 'graphql-api-google-translate-dist',
],
// Events Manager
[
'path' => 'layers/GraphQLAPIForWP/plugins/events-manager',
'zip_file' => 'graphql-api-events-manager.zip',
'main_file' => 'graphql-api-events-manager.php',
'dist_repo_organization' => 'GraphQLAPI-PRO',
'dist_repo_name' => 'graphql-api-events-manager-dist',
],
];
}
}
GitHub Actions lädt Workflows nur aus .github/workflows, und die vorgelagerten Workflows befinden sich unter submodules/PoP/.github/workflows; daher müssen wir sie kopieren. Das ist nicht ideal, obwohl wir vermeiden können, die kopierten Workflows zu bearbeiten und die vorgelagerten Dateien als einzige Wahrheitsquelle zu behandeln.
Zum Kopieren der Workflows kann ein einfacher Composer-Skript verwendet werden.
{
"scripts": {
"copy-workflows": [
"php -r \"copy('submodules/PoP/.github/workflows/generate_plugins.yml', '.github/workflows/generate_plugins.yml');\"",
"php -r \"copy('submodules/PoP/.github/workflows/split_monorepo.yaml', '.github/workflows/split_monorepo.yaml');\""
]
}
}
Dann, jedes Mal, wenn ich die Workflows im vorgelagerten Monorepo bearbeite, kopiere ich sie auch in das nachgelagerte Monorepo, indem ich den folgenden Befehl ausführe.
composer copy-workflows
Sobald dieses Setup vorhanden ist, generiert das private Repository seine eigenen Plugins, indem es den Workflow aus dem öffentlichen Repository wiederverwendet.

Ich bin mit diesem Ansatz äußerst zufrieden. Ich habe das Gefühl, dass er mir die gesamte Last der Projektverwaltung abgenommen hat. Ich habe von einem WordPress-Plugin-Autor gelesen, der sich beschwerte, dass die Verwaltung der Veröffentlichungen seiner 10+ Plugins eine beträchtliche Zeit in Anspruch nahm. Das passiert hier nicht – nachdem ich meinen Pull-Request zusammengeführt habe, werden sowohl öffentliche als auch private Plugins automatisch generiert, wie Magie.
Probleme mit dem Multi-Monorepo
Zunächst einmal, es leckt. Idealerweise sollte leoloso/PoP vollständig autonom sein und nicht wissen, dass es als vorgelagertes Monorepo in einem größeren Schema verwendet wird – aber das ist nicht der Fall.
Beim Ausführen von git checkout muss das nachgelagerte Monorepo die Option --recurse-submodules übergeben, um auch die Submodule auszuchecken. In den GitHub Actions-Workflows für das private Repo muss der Checkout so erfolgen
- uses: actions/checkout@v2
with:
submodules: recursive
Daher müssen wir submodules: recursive zum nachgelagerten Workflow hinzufügen, aber nicht zum vorgelagerten, obwohl beide dieselbe Quelldatei verwenden.
Um dies zu lösen und das öffentliche Monorepo als einzige Wahrheitsquelle beizubehalten, werden die Workflows in leoloso/PoP der Wert für submodules über eine Umgebungsvariable CHECKOUT_SUBMODULES injiziert, wie hier.
env:
CHECKOUT_SUBMODULES: "";
jobs:
provide_data:
steps:
- uses: actions/checkout@v2
with:
submodules: ${{ env.CHECKOUT_SUBMODULES }}
Der Umgebungswert ist für das vorgelagerte Monorepo leer, daher funktioniert submodules: "" gut. Und dann, beim Kopieren der Workflows vom vorgelagerten zum nachgelagerten System, ersetze ich den Wert der Umgebungsvariable durch "recursive", sodass es wird
env:
CHECKOUT_SUBMODULES: "recursive"
(Ich habe einen PHP-Befehl, um die Ersetzung durchzuführen, aber wir könnten auch sed im copy-workflows Composer-Skript verwenden.)
Dieses Leck offenbart ein weiteres Problem mit diesem Setup: Ich muss alle Beiträge zum öffentlichen Repository überprüfen, bevor sie zusammengeführt werden, sonst könnten sie etwas im nachgelagerten System kaputt machen. Die Mitwirkenden wären sich dieser Lecks völlig unbewusst (und könnten dafür nicht beschuldigt werden). Diese Situation ist spezifisch für das öffentliche/private Monorepo-Setup, bei dem ich die einzige Person bin, die sich des vollständigen Setups bewusst ist. Während ich Zugriff auf das öffentliche Repository teile, bin ich der Einzige, der auf das private zugreift.
Als Beispiel dafür, wie die Dinge schiefgehen könnten, könnte ein Mitwirkender von leoloso/PoP CHECKOUT_SUBMODULES: "" entfernen, da es überflüssig ist. Was der Mitwirkende nicht weiß, ist, dass diese Zeile zwar nicht benötigt wird, aber das Entfernen das private Repository kaputt macht.
Ich denke, ich muss eine Warnung hinzufügen!
env:
### ☠️ Do not delete this line! Or bad things will happen! ☠️
CHECKOUT_SUBMODULES: ""
Zusammenfassung
Mein Repository hat eine ziemliche Reise hinter sich und wurde im Laufe der Zeit an die neuen Anforderungen meines Codes und meiner Anwendung angepasst.
- Es begann als ein einziges Repository, das eine monolithische App hostete.
- Es wurde zu einem Multi-Repository, als die App in Pakete aufgeteilt wurde.
- Es wurde auf ein Monorepo umgestellt, um alle Pakete besser verwalten zu können.
- Es wurde zu einem Multi-Monorepo aufgerüstet, um Dateien mit einem privaten Monorepo zu teilen.
Kontext ist alles, also gibt es hier keinen "besten" Ansatz – nur Lösungen, die für verschiedene Szenarien mehr oder weniger geeignet sind.
Hat mein Repository das Ende seiner Reise erreicht? Wer weiß? Das Multi-Monorepo erfüllt meine aktuellen Anforderungen, aber es hostet alle privaten Plugins zusammen. Wenn ich jemals Auftragnehmern den Zugriff auf ein bestimmtes privates Plugin gewähren muss, während ich ihnen den Zugriff auf anderen Code verweigere, dann ist das Monorepo möglicherweise nicht mehr die ideale Lösung für mich, und ich muss erneut iterieren.
Ich hoffe, die Reise hat Ihnen gefallen. Und wenn Sie Ideen oder Beispiele aus Ihren eigenen Erfahrungen haben, würde ich mich freuen, sie in den Kommentaren zu hören.
Ich würde empfehlen, GitHub Projects dafür zu verwenden.
Ich verwende sie für allgemeines Management (insbesondere Statusverfolgung), aber das ist eines der Dinge, für die sie entwickelt wurden (das andere Hauptding ist die Organisation von Gruppen zusammenhängender Issues, z. B. mehrere Issues für ein einzelnes Feature).
Wow! Was für eine Reise!
Es ist sehr interessant zu sehen, wie Sie diese Probleme im Laufe all dieser Jahre gelöst haben.
Danke fürs Teilen
Seien Sie vorsichtig mit Monorepos, wenn es um gemeinsame Abhängigkeiten geht. Sobald etwas dieselbe Paketierung benötigt (aber eine bestimmte Version), wird die Aktualisierung zum Kopfzerbrechen. Ich habe den Fehler gemacht, eine Create React App-Instanz als Geschwisterpaket zu einer Komponentbibliothek zu verwenden. Sie müssen entweder das Hosten gemeinsamer Ressourcen wie React, Babel, ESLint, Jest usw. vermeiden oder manuell die CRA-Versionen über alle Pakete hinweg abgleichen (CRA aktualisiert seine Abhängigkeiten langsam).
Ich bin mir nicht sicher, was ich von Multi-Mono-Repos halte. Interessant, aber es scheint eine ganz neue Ebene von beweglichen Teilen zu geben, die verwaltet werden müssen. Insbesondere wenn Sie sich für Dinge wie Repository-Management-Tools wie Conventional Commits, Commit-Linting usw. interessieren.
Das muss ich mir noch einmal durchlesen, vielleicht ein drittes Mal. Danke fürs Teilen.
Mein erster Eindruck veranlasst mich zu fragen – und das ist eine Standardfrage, auf die wir uns alle öfter stützen sollten – "Was passiert, wenn Sie von einem Bus überfahren werden?"
Mein Gefühl ist, dass es für jemanden, der einsteigt und das Ruder übernimmt, überwältigend, wenn nicht sogar gefährlich sein könnte. Was passiert dann mit dem Produkt? Und mit den Kunden, die es nutzen?
Wartbarer Code und Prozesse sind wichtig, aber werden zu oft übersehen. Ich sage nicht, dass das hier der Fall ist, aber wenn 80 % davon von Ihnen abhängen und einzigartig für Sie sind, dann nein, Ihre Reise ist noch nicht zu Ende :)
Eine großartige Analyse der Vor- und Nachteile jedes Ansatzes! Es scheint jedoch, dass noch ein letzter Schritt fehlt: Entdecken Sie Git X-Modules und verwenden Sie denselben "Multi-Monorepo"-Ansatz ohne die Probleme, die durch Submodule verursacht werden. Submodule sind in der Tat ziemlich ernst, wenn man in einem Team arbeitet, in dem jeder die Arbeit anderer ruinieren kann.
Ich verwende Turborepo für eines meiner Vue-Projekte. Derzeit habe ich eine Situation in meiner Organisation. Wir haben ein Monorepo (Turborepo) für eine Client/Server-Webanwendung eingerichtet. und wollen einen Auftragnehmer einstellen, der an der Gestaltung eines Teils des Clients arbeitet. Wir beabsichtigen, dem Auftragnehmer nur Zugang zum relevanten Code zu gewähren.
Löst Ihre Lösung ein solches Problem? Danke
Könnte ein solcher Ansatz verwendet werden, um schreibbare Unterprojekte zu haben?
Ein privates Mono-Repo für den internen Gebrauch, aber die öffentlich zugänglichen Unterprojekte sind diejenigen, die PRs von der Öffentlichkeit erhalten.
Grund: Unterschiedliche Lizenzen. (Andernfalls eng gekoppelt, der Grund für den Monorepo-Wunsch)