Mit extends einen gemeinsamen Basis-Layer für Multi-Brand-Setups aufbauen
Über die extends-Property in der nuxt.config.ts lassen sich ganze Nuxt-Projekte als Basis-Layer wiederverwenden, inklusive Komponenten, Composables, Layouts und Konfiguration. Für Multi-Brand-Setups mit einem gemeinsamen Kern und markenspezifischen Overrides ist das oft eine leichtgewichtigere Lösung als ein klassisches Monorepo mit separaten npm-Paketen.
Inhaltsverzeichnis
- 1. Was sind Nuxt Layers?
- 2. Die extends-Property im Detail
- 3. Praxisbeispiel: Ein Basis-Layer mit gemeinsamen Komponenten
- 4. Anwendungsfall: Multi-Brand-Setup
- 5. Markenspezifische Overrides
- 6. Reihenfolge und Auflösung von Layers
- 7. Unterschied zu einem klassischen Monorepo mit geteilten npm-Paketen
- 8. Grenzen und Fallstricke von Nuxt Layers
- 9. Fazit: Layers als leichtgewichtige Alternative
- 10. Zusammenfassung
- 11. FAQ
1. Was sind Nuxt Layers?
Ein Nuxt Layer ist im Kern nichts anderes als ein eigenständiges Nuxt-Verzeichnis mit der gewohnten Ordnerstruktur aus components, composables, pages, layouts und einer eigenen nuxt.config.ts. Ein solcher Layer lässt sich in einem anderen Nuxt-Projekt als Grundlage einbinden, wodurch alle darin enthaltenen Komponenten, Composables und Konfigurationswerte automatisch für das einbindende Projekt zur Verfügung stehen, ganz ohne manuellen Import.
Das Konzept eignet sich besonders für Situationen, in denen mehrere Anwendungen einen erheblichen Teil ihrer Funktionalität teilen, sich aber in Details wie Branding, einzelnen Seiten oder spezifischen Features unterscheiden. Statt Code über Copy-Paste oder ein separates npm-Paket zu teilen, wird der gemeinsame Kern als Layer ausgelagert und von jeder Anwendung über die extends-Property referenziert.
2. Die extends-Property im Detail
Die extends-Property in der nuxt.config.ts nimmt einen Pfad, ein Array von Pfaden oder sogar eine Git-Quelle entgegen und lädt den referenzierten Layer, bevor die eigene Konfiguration angewendet wird. Nuxt führt dabei automatisch ein tiefes Merge für Konfigurationsoptionen, Komponenten-Verzeichnisse, Composables-Auto-Imports und Layout-Definitionen durch, sodass sich Basis-Layer und aufrufendes Projekt nahtlos zu einer einzigen Anwendung zusammenfügen.
Layer können dabei selbst wieder andere Layer per extends einbinden, wodurch sich Hierarchien mit mehreren Ebenen aufbauen lassen, etwa ein sehr generischer Basis-Layer für alle Marken, darauf aufbauend ein regionaler Layer für bestimmte Länder, und ganz oben die konkrete, markenspezifische Anwendung. Jede Ebene kann dabei gezielt Teile der darunterliegenden Ebenen überschreiben.
3. Praxisbeispiel: Ein Basis-Layer mit gemeinsamen Komponenten
Im folgenden Beispiel liegt ein Basis-Layer im Verzeichnis layers/base und enthält eine gemeinsame Header-Komponente sowie eine geteilte Runtime-Config für die API-Basis-URL. Zwei markenspezifische Anwendungen binden diesen Layer über extends ein und ergänzen jeweils nur ihre eigenen, markenspezifischen Seiten und Farbwerte.
Wichtig ist dabei, dass Komponenten aus dem Basis-Layer in der konkreten Anwendung ganz normal ohne zusätzlichen Import verwendet werden können, genau wie lokale Komponenten. Überschreibt die Anwendung eine Komponente mit demselben Namen lokal, hat die lokale Version automatisch Vorrang vor der Version aus dem Layer.
// layers/base/nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
apiBase: 'https://api.example.com',
},
},
});
// layers/base/components/AppHeader.vue
// <template><header>Gemeinsamer Header für alle Marken</header></template>
// apps/brand-a/nuxt.config.ts
export default defineNuxtConfig({
extends: ['../../layers/base'],
app: {
head: { title: 'Marke A' },
},
runtimeConfig: {
public: {
themeColor: '#0066cc',
},
},
});
4. Anwendungsfall: Multi-Brand-Setup
Ein klassisches Multi-Brand-Setup entsteht, wenn ein Unternehmen mehrere Marken mit weitgehend identischer Funktionalität betreibt, etwa denselben Checkout-Prozess, dieselbe Produktsuche und dieselbe Kontostruktur, aber jeweils eigenem Branding, eigener Domain und teils eigenen Zusatzfeatures. Ohne geteilte Basis müsste jede Änderung an der gemeinsamen Logik in jeder Marke einzeln nachgezogen werden, was schnell zu Inkonsistenzen führt.
Mit einem Basis-Layer wird die gemeinsame Logik, also Composables für den Warenkorb, gemeinsame UI-Komponenten und geteilte Middleware, an genau einer Stelle gepflegt. Jede markenspezifische Anwendung bindet diesen Layer ein und ergänzt nur, was tatsächlich markenspezifisch ist: Logo, Farbpalette, spezielle Landingpages oder abweichende Zahlungsanbieter.
5. Markenspezifische Overrides
Overrides funktionieren in Nuxt Layers über die Dateisystem-Konvention: Legt die konkrete Anwendung eine Datei mit demselben relativen Pfad wie im Basis-Layer an, etwa components/AppHeader.vue, gewinnt die Version der Anwendung. Dasselbe Prinzip gilt für Seiten, Layouts und Composables, wodurch sich gezielt einzelne Bausteine ersetzen lassen, ohne den gesamten Layer zu duplizieren.
Für Konfigurationswerte wie runtimeConfig greift stattdessen ein tiefes Merge: Werte aus der Anwendung ergänzen oder überschreiben die Werte aus dem Layer, ohne dass nicht explizit gesetzte Werte verloren gehen. Das erlaubt es, im Basis-Layer sinnvolle Standardwerte zu definieren und in der konkreten Anwendung nur die tatsächlich abweichenden Werte anzupassen.
6. Reihenfolge und Auflösung von Layers
Werden mehrere Layer über ein Array in extends eingebunden, werden sie in der angegebenen Reihenfolge verarbeitet, wobei später genannte Layer Vorrang vor früher genannten haben. Das aufrufende Projekt selbst hat dabei immer die höchste Priorität und kann jeden Wert aus jedem eingebundenen Layer überschreiben.
Bei tief verschachtelten Layer-Hierarchien lohnt es sich, die Auflösungsreihenfolge zu dokumentieren, da Fehler in der Praxis oft daraus entstehen, dass ein Entwickler nicht mehr genau weiß, aus welcher Ebene ein bestimmter Konfigurationswert oder eine bestimmte Komponente tatsächlich stammt. Ein klar benannter, flacher Layer-Baum ist meist wartungsfreundlicher als viele tief verschachtelte Ebenen.
7. Unterschied zu einem klassischen Monorepo mit geteilten npm-Paketen
Ein klassischer Monorepo-Ansatz teilt Code über eigenständige npm-Pakete, die versioniert, gebaut und explizit importiert werden müssen. Das bringt saubere Versionsgrenzen mit sich, verursacht aber auch zusätzlichen Aufwand: Ein gemeinsames Paket muss bei Änderungen neu gebaut und in den abhängigen Projekten aktualisiert werden, bevor die Änderung dort sichtbar wird.
Nuxt Layers verzichten auf diesen Build- und Versionierungsschritt vollständig. Ein Layer wird zur Build-Zeit direkt in das aufrufende Projekt eingebunden, Änderungen am Layer sind im Entwicklungsmodus sofort im abhängigen Projekt sichtbar, ganz ohne separaten Publish-Schritt. Der Preis dafür ist weniger strikte Versionskontrolle, was für eng zusammenarbeitende Teams im selben Repository meist ein guter Kompromiss ist, für vollständig unabhängige Teams mit eigenem Release-Zyklus aber ein Nachteil sein kann.
8. Grenzen und Fallstricke von Nuxt Layers
Ein häufiger Fallstrick ist die Annahme, Layer würden wie unabhängige, isolierte Module funktionieren. Tatsächlich werden alle Layer und das aufrufende Projekt zu einer einzigen Nuxt-Anwendung zusammengeführt, weshalb Namenskollisionen bei Komponenten, Composables oder Routen zwischen verschiedenen Layern zu unerwartetem Verhalten führen können, wenn sie nicht bewusst als Override gedacht sind.
Auch Abhängigkeiten aus der package.json eines Layers werden nicht automatisch installiert, wenn der Layer als lokaler Ordner eingebunden wird. Nutzt ein Basis-Layer eine bestimmte Bibliothek, muss diese in der Regel auch in der package.json der konkreten Anwendung als Abhängigkeit geführt werden, was bei der Planung eines Layer-Systems leicht übersehen wird. Ein sinnvoller Ansatz ist deshalb, alle vom Basis-Layer benötigten Bibliotheken zentral zu dokumentieren, damit neue markenspezifische Anwendungen von Anfang an mit einer vollständigen Abhängigkeitsliste starten.
9. Fazit: Layers als leichtgewichtige Alternative
Nuxt Layers bieten eine leichtgewichtige Möglichkeit, mehrere eng verwandte Anwendungen auf einer gemeinsamen Basis aufzubauen, ohne den organisatorischen Aufwand eines klassischen Monorepos mit separat versionierten Paketen. Für Multi-Brand-Setups, bei denen der Großteil der Logik identisch ist und sich nur Branding sowie einzelne Details unterscheiden, ist das Konzept besonders gut geeignet.
Wer mit Layers arbeitet, sollte die Verantwortlichkeiten zwischen Basis-Layer und konkreter Anwendung klar dokumentieren und Namenskollisionen bewusst vermeiden, statt sich blind auf implizites Überschreiben zu verlassen. Bei wachsender Komplexität mit vielen unabhängigen Teams kann sich später dennoch der Umstieg auf ein Monorepo mit echten, versionierten Paketen lohnen.
| Aspekt | Nuxt Layers (extends) | Monorepo mit npm-Paketen |
|---|---|---|
| Einbindung | Direkt zur Build-Zeit über extends | Expliziter Import eines Pakets |
| Änderungen sichtbar | Sofort im Dev-Modus | Erst nach Build und Update der Abhängigkeit |
| Versionskontrolle | Kein separates Versionsschema | Eigene Versionsnummern pro Paket |
| Setup-Aufwand | Gering, reine Ordnerstruktur | Höher, Build-Pipeline pro Paket nötig |
| Am besten geeignet für | Eng zusammenarbeitende Teams, ähnliche Apps | Unabhängige Teams, eigener Release-Zyklus |
Mironsoft
Vue-Architektur, Composition API und Nuxt-Performance
Vue-Anwendungen, die mit jedem Feature nicht komplizierter werden?
Wir prüfen bestehende Vue- und Nuxt-Projekte auf unstrukturierte Composables, ungenutzte Reaktivität und aufgeblähte Bundles und bauen daraus eine Architektur, die neue Features aufnimmt, ohne die Codebasis unübersichtlicher zu machen.
Architektur-Review
Composables, State-Management und Komponentenstruktur auf Wartbarkeit prüfen.
Performance-Audit
Reaktivitäts-Overhead, Bundle-Größe und Nuxt-Rendering-Strategie systematisch optimieren.
Nuxt-Integration
SSR/SSG-Setup und API-Anbindung robust und typsicher aufbauen.
10. Zusammenfassung
Nuxt Layers für geteilte Konfiguration: Das Wichtigste auf einen Blick
Kernmechanismus
extends-Property in der nuxt.config.ts für geteilte Basis-Layer
Haupteffekt
Gemeinsame Komponenten, Composables und Config ohne npm-Paket
Typischer Anwendungsfall
Multi-Brand-Setup mit gemeinsamem Kern und markenspezifischen Overrides
Abgrenzung
Kein Build- oder Versionierungsschritt wie bei klassischen Monorepo-Paketen