Theme-Struktur
Jedes Theme unter _theme/ ist ein eigenstaendiges Nuxt-4-Projekt. Diese Seite zeigt die vollstaendige Ordner-Struktur am Beispiel _theme/vue-base/, erklaert jeden Bereich und zeigt Custom-Overrides fuer Plugin-Layouts und Widgets.
Top-Level eines Themes
_theme/vue-base/
├── app/ # Nuxt App-Verzeichnis (Nuxt 4 Convention)
├── public/ # Statische Assets (ueber Root-URL verfuegbar)
├── server/ # Server-Side-Middleware, API-Routes
├── node_modules/ # npm-Dependencies
├── .nuxt/ # Nuxt-Build-Output (git-ignored)
├── .output/ # Production-Build-Output (git-ignored)
├── .env # Theme-spezifische Env-Variablen
├── .htaccess # Apache-Regeln (falls Theme ueber Apache geliefert wird)
├── nuxt.config.ts # Nuxt-Konfiguration
├── package.json # Dependencies, Build-Scripts
├── package-lock.json
├── tsconfig.json
├── app.cjs # Ggf. Legacy-Einstieg
├── deploy.sh # Ggf. Projekt-Deploy-Script
└── README.mdDer entscheidende Teil ist app/ (Nuxt App) — dort lebt der gesamte Theme-Code.
app/ — Nuxt-App
app/
├── app.vue # Root-Komponente (Layout-Wrapper)
├── components/ # Vue-Komponenten
│ ├── AppFooter.vue # Frontend-Footer
│ ├── AppHeader.vue # Frontend-Header
│ ├── AppMenuEditor.vue # Menu-Editor-Frontend
│ ├── AppPagebuilder.vue # Pagebuilder-Einstieg (laedt Rows → Cols → Widgets)
│ ├── admin/ # Ns* Admin-UI (NsModal, NsForm, NsTable, MediaManager, ...)
│ └── pagebuilder/ # Pagebuilder-Rendering
│ ├── PagebuilderRow.vue
│ ├── PagebuilderColumn.vue
│ └── PagebuilderWidget.vue
├── composables/ # Composables (useSeoHead, useSchemaOrg, useUserCenter, ...)
├── layouts/ # Nuxt Layouts (admin.vue, admin-login.vue, default.vue)
├── middleware/ # Route-Middleware
├── pages/ # File-based Routing
│ ├── admin/
│ │ └── [...slug].vue # EINZIGE Admin-Route — kein index.vue!
│ └── [...slug].vue # Frontend-Catch-all
├── plugins/ # Nuxt-Plugins (siehe Tabelle unten)
├── stores/ # Pinia-Stores (admin.ts, auth.ts, layout.ts)
├── utils/ # Hilfs-Funktionen
└── widgets/ # Pagebuilder-Widget-Registry (auto-generiert!)
└── plugin-registry.js # NICHT MANUELL EDITIERENWidget-Komponenten leben nicht hier
Pagebuilder-Widget-Komponenten (Testimonials, Banner, Shop-Listings, …) liegen nicht in components/widgets/, sondern unter _public/extensions/core/backend/{plugin}/widgets/{widget_template}/template/index.vue. Siehe Widgets › Widget-Anatomie.
Keine admin/index.vue
Das Admin-Routing ist ein einziger Catch-all-Route: app/pages/admin/[...slug].vue. Kein index.vue darunter — der Nuxt-Router wuerde sonst Konflikte erzeugen. Alle Admin-Plugins werden ueber import.meta.glob dynamisch in diese Route geladen.
components/admin/ — Backend-UI-Bausteine
Das Admin-UI nutzt einen gemeinsamen Satz wiederverwendbarer Komponenten mit Ns-Prefix:
| Komponente | Zweck |
|---|---|
NsTable | Listen mit PrimeVue DataTable, Pagination, Suche |
NsForm | Dynamische Formular-Rendering aus Plugin-Config |
NsModal | Modals mit Sprach-Tabs, Bootstrap 5-basiert |
NsSelect | TomSelect-Wrapper fuer durchsuchbare Dropdowns |
NsModuleList | Sub-Listen im Modal (show_module_list-Button) |
NsTemplate | Loader fuer template-Construct-Plugins |
NsDetail | Detail-Ansicht fuer content_construct=table |
NsCustomContent | Renderer fuer show_custom_content-Button |
MediaManager | File-Picker mit Tree-Navigation + Upload |
Details zu diesen Komponenten: Skill php-backend-check (references/vue-components.md).
plugins/ — Nuxt-Plugins
| Plugin | Client/Server | Zweck |
|---|---|---|
ab-tracking.client.ts | client | A/B-Test-Impression/Conversion-Tracking |
admin-css.client.ts | client | CSS-Isolation fuer /admin (laedt nur dort Admin-Styles) |
admin-i18n.ts | beides | Admin-Uebersetzungen (laeuft auch in SSR, damit First-Paint lokalisiert ist) |
ai-admin.client.ts | client | AI-Feature-Injection in Admin-Formulare (data-aifeature-Attribute) |
ckeditor.client.ts | client | CKEditor 5 Setup fuer textarea-Felder mit Rich-Text |
cookieconsent.client.ts | client | Cookie-Consent-Banner (4 Kategorien) |
gsap-animations.client.ts | client | GSAP-Scroll-Animationen, lazy-loaded |
primevue.ts | beides | PrimeVue-Setup (Basis fuer NsTable DataTable) |
widgets.client.ts | client | Plugin-Widget-Registrierung (User-Center-Items etc.) |
.client.ts-Suffix bedeutet: nur im Browser laufen, nicht in SSR. Plugins ohne Suffix (admin-i18n.ts, primevue.ts) laufen auch in SSR — das ist bei PrimeVue noetig fuer serverseitiges Markup der DataTable und bei i18n fuer lokalisiertes First-Paint.
stores/ — Pinia-Stores
| Store | Zweck |
|---|---|
admin.ts | Aktiver Plugin, Navigation, systemVersion |
auth.ts | Frontend-Auth-Session (Login-Status, User-Profil) |
layout.ts | Mobile-Menu-Status, Menu-Editor-State |
Plugin-spezifische Stores (z. B. sw6Store.ts fuer Shopware-6-Cart/Customer/Config) leben nicht im Theme, sondern im jeweiligen Plugin unter _public/extensions/core/backend/{plugin}/widgets/.../. So bleibt der Store mitsamt seiner Logik gebuendelt beim Plugin und wird beim De-/Installieren automatisch mitgefuehrt.
public/ — Statische Assets
public/
├── backend/
│ ├── css/
│ │ ├── style.less # Admin Light-Theme (Glassmorphism)
│ │ ├── style-darkmode.less # Admin Dark-Theme
│ │ └── index.less # LESS-Einstiegspunkt
│ └── js/
│ └── pagebuilder/ # Preview-Overlay-Scripts (postMessage)
├── css/ # Frontend-spezifische Styles
├── fonts/ # Font-Dateien
├── favicon.ico
└── robots.txtDie Dateien hier liegen unter dem Root-URL-Pfad — public/favicon.ico → /favicon.ico.
Admin-Styling-Details: Skill NewSemantics-Backend-Layout.
server/ — Server-Side
Nuxt-Server-Middleware und API-Routes. Im CMS aktuell leichtgewichtig — die meisten API-Calls gehen direkt an den PHP-Backend (/api/*), nicht an Nuxt-Server-Routes.
nuxt.config.ts
Die zentrale Nuxt-Konfiguration. Die wichtigsten Bereiche:
export default defineNuxtConfig({
// Nuxt-Module (@pinia/nuxt, @nuxt/image, @vueuse/nuxt, ...)
modules: [ /* ... */ ],
// Runtime-Config (Env-Variablen)
runtimeConfig: {
apiKey: process.env.NUXT_API_KEY,
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE,
siteUrl: process.env.NUXT_PUBLIC_SITE_URL || '',
theme: process.env.NUXT_PUBLIC_THEME || 'vue-base',
}
},
// Cross-Plugin-Aliases
alias: {
'#extensions': resolve(process.cwd(), '../../_public/extensions/core/backend'),
'#widgets/plugin-registry': resolve(process.cwd(), 'app/widgets/plugin-registry.js'),
},
// Vite + PurgeCSS-Safelist
vite: {
plugins: [
purgecss({
safelist: {
standard: [ /^swiper/, /^fa-/, /^ns-/, /* ... */ ],
greedy: [ /^row_/, /^col_/, /^widget_/, /* ... */ ],
deep: [ /data-animation/ ]
}
})
]
}
})Details zu Env-Variablen: Environment-Variablen. Details zu Aliases: Nuxt-Aliases.
.env
NUXT_API_KEY=123456
NUXT_PUBLIC_API_BASE=https://demo.new-semantics.com/api
NUXT_PUBLIC_SITE_URL=https://demo.new-semantics.com
NUXT_PUBLIC_THEME=vue-baseProjektspezifische Safelist-Erweiterungen kommen ebenfalls ins .env — siehe Environment-Variablen › PurgeCSS-Safelist.
package.json — Scripts
{
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview"
}
}Jedes Theme hat seinen eigenen Build — npm install und npm run build geschehen im Theme-Ordner, nicht im Projekt-Root. Details: Deployment.
Custom-Overrides (Theme-spezifisch)
Themes koennen Plugin-Layouts und Widget-Templates uebersteuern, ohne den Plugin-Code anzufassen:
_theme/{theme}/app/custom/{plugin}/widgets/{widget_template}/template/index.vueZum Beispiel kann ein Projekt-Theme das categoryBannerNoLink-Widget ueberschreiben:
_theme/projekt01/app/custom/shop/widgets/categoryBannerNoLink/template/index.vueDer vueRegistry-Rebuild (/admin/cache) bevorzugt diese Datei vor der Original-Version aus _public/extensions/core/backend/shop/widgets/categoryBannerNoLink/template/index.vue. Details: Widgets › Widget-Anatomie › Custom-Theme-Overrides.
Analog fuer Menu-Styling: jedes Theme kann ein eigenes public/css/menu.less haben, das ueber den compiled_css-Endpoint vom Menu-Editor geladen wird.
Theme-Varianten: vue-base vs. projekt01
| Aspekt | vue-base | projekt01 |
|---|---|---|
| Zweck | Default/Produktiv-Theme | Projekt-Fork fuer Kunden-Customizing |
app/ | Voll ausgestattet | Kopie + Anpassungen |
nuxt.config.ts | System-Default | Projekt-Safelist, eigene Aliases |
custom.less (via /admin/design) | Standard-Tokens | Projekt-Tokens |
| Custom-Overrides | keine | app/custom/* uebersteuert Plugin-Widgets |
Ein neuer Projekt-Fork kopiert vue-base/ vollstaendig und benennt den Ordner um — der Build-Prozess und alle Konventionen bleiben identisch.
Haeufige Fehler
app/pages/admin/index.vue angelegt
Die Nuxt-Router-Konvention bricht — catch-all plus index fuehrt zu kollidierenden Routes. Nur [...slug].vue nutzen.
.env nicht geladen
Nuxt laedt .env automatisch aus dem Theme-Root (nicht aus dem Projekt-Root). Env-Variablen muessen im jeweiligen Theme-Ordner stehen, nicht zentral.
Shared Code in _theme/base/ importiert, aber nicht aufgeloest
_theme/base/ ist kein npm-Package — es wird per relativer Pfad oder Nuxt-Alias eingebunden. Details zu Aliases: Nuxt-Aliases.
plugin-registry.js manuell editiert
Die Datei wird beim Cache-Rebuild aus allen Widget-Ordnern neu generiert. Aenderungen gehen verloren. Fuer Widget-Aenderungen immer das Widget-Template selbst editieren.
Theme-Wechsel ohne npm install
Jedes Theme hat eigene node_modules/. Ein Wechsel von vue-base zu projekt01 braucht npm install im neuen Ordner.
Siehe auch
- Themes-Uebersicht — Theme-Konzept und
NUXT_PUBLIC_THEME - Environment-Variablen — alle Env-Variablen mit Erklaerung
- Design-Tokens — LESS-Tokens + Admin-UI
- Nuxt-Aliases —
#extensions,#widgets/plugin-registry - Deployment — Production-Build, nginx, Update-Manager
- Widgets › Widget-Anatomie — Theme-Widget-Overrides
- Plugins › Plugin-Anatomie — Admin-Plugin-Layouts unter
_public/extensions/