Vite-Integration
Moderne JavaScript-Anwendungen brauchen ausgereifte Build-Werkzeuge. Nette Assets bietet eine erstklassige Integration von Vite, dem Frontend-Build-Werkzeug der nächsten Generation. Sie bekommen blitzschnelle Entwicklung mit Hot Module Replacement (HMR) und optimierte Produktions-Builds ohne Konfigurationsaufwand.
- Keine Konfiguration nötig – automatische Brücke zwischen Vite und PHP-Templates
- Vollständige Verwaltung der Abhängigkeiten – ein Tag kümmert sich um alle Assets
- Hot Module Replacement – sofortige Aktualisierung von JavaScript und CSS
- Optimierte Produktions-Builds – Code Splitting und Tree Shaking
Nette Assets bindet Vite nahtlos ein, sodass Sie all diese Vorteile bekommen und Ihre Templates trotzdem wie gewohnt schreiben.
Vite einrichten
Richten wir Vite Schritt für Schritt ein. Keine Sorge, wenn Build-Werkzeuge für Sie neu sind – wir erklären alles!
Schritt 1: Vite installieren
Installieren Sie zuerst Vite und das Nette-Plugin in Ihrem Projekt:
npm install -D vite @nette/vite-plugin
Damit werden Vite und ein spezielles Plugin installiert, das Vite hervorragend mit Nette zusammenarbeiten lässt.
Schritt 2: Projektstruktur
Üblich ist es, die Quelldateien der Assets in einem Ordner assets/ im Wurzelverzeichnis des Projekts abzulegen
und die kompilierten Fassungen in www/assets/:
web-project/ ├── assets/ ← Quelldateien (SCSS, TypeScript, Quellbilder) │ ├── public/ ← statische Dateien (unverändert kopiert) │ │ └── favicon.ico │ ├── images/ │ │ └── logo.png │ ├── app.js ← Haupt-Einstiegspunkt │ └── style.css ← Ihre Styles └── www/ ← öffentliches Verzeichnis (Document-Root) ├── assets/ ← hier landen die kompilierten Dateien └── index.php
Der Ordner assets/ enthält Ihre Quelldateien – den Code, den Sie schreiben. Vite verarbeitet diese Dateien und
legt die kompilierten Fassungen in www/assets/ ab.
Schritt 3: Vite konfigurieren
Legen Sie im Wurzelverzeichnis des Projekts eine Datei vite.config.ts an. Diese Datei sagt Vite, wo es Ihre
Quelldateien findet und wohin es die kompilierten legen soll.
Das Nette-Vite-Plugin bringt sinnvolle Standardwerte mit, die die Konfiguration einfach machen. Es geht davon aus, dass Ihre
Frontend-Quelldateien im Verzeichnis assets/ liegen (Option root) und die kompilierten Dateien nach
www/assets/ gehen (Option outDir). Sie müssen nur den Einstiegspunkt
angeben:
import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';
export default defineConfig({
plugins: [
nette({
entry: 'app.js',
}),
],
});
Unter der Haube setzt das Plugin außer root und outDir noch einige weitere Vite-Optionen, damit
alles zusammenpasst: base auf '' (die Assets werden direkt vom Document-Root ausgeliefert),
build.manifest auf true (damit Nette Assets die gehashten Dateinamen zuordnen kann) und
build.assetsDir auf '' (die kompilierten Dateien landen direkt in outDir, ohne einen
Unterordner static/). Jede davon können Sie überschreiben.
Der Standardwert von outDir (www/assets) setzt voraus, dass das Verzeichnis
www/ bereits existiert. Tut es das nicht, bricht das Plugin mit dem Fehler “The output directory … does not
exist” ab.
Wenn Sie einen anderen Verzeichnisnamen für den Build Ihrer Assets angeben wollen, müssen Sie einige Optionen ändern:
export default defineConfig({
root: 'assets', // Wurzelverzeichnis der Quell-Assets
build: {
outDir: '../www/assets', // wohin die kompilierten Dateien gehen
},
// ... weitere Konfiguration ...
});
Der Pfad outDir gilt als relativ zu root, deshalb steht am Anfang ../.
Schritt 4: Nette konfigurieren
Teilen Sie Nette Assets in Ihrer common.neon von Vite mit:
assets:
mapping:
default:
type: vite # sagt Nette, dass es den ViteMapper verwenden soll
path: assets
Schritt 5: Skripte hinzufügen
Ergänzen Sie diese Skripte in Ihrer package.json:
{
"scripts": {
"dev": "vite",
"build": "vite build"
}
}
Nun können Sie:
npm run dev– den Entwicklungsserver mit Hot Reloading startennpm run build– optimierte Produktionsdateien erzeugen
Einstiegspunkte
Ein Einstiegspunkt ist die Hauptdatei, in der Ihre Anwendung beginnt. Aus dieser Datei importieren Sie weitere Dateien (CSS, JavaScript-Module, Bilder) und erzeugen so einen Abhängigkeitsbaum. Vite folgt diesen Importen und bündelt alles zusammen.
Beispiel für einen Einstiegspunkt assets/app.js:
// Styles importieren
import './style.css'
// JavaScript-Module importieren
import netteForms from 'nette-forms';
import naja from 'naja';
// Die Anwendung initialisieren
netteForms.initOnLoad();
naja.initialize();
Im Template können Sie einen Einstiegspunkt so einfügen:
{asset 'app.js'}
Nette Assets erzeugt automatisch alle nötigen HTML-Tags – JavaScript, CSS und alle weiteren Abhängigkeiten.
Mehrere Einstiegspunkte
Größere Anwendungen brauchen oft getrennte Einstiegspunkte:
export default defineConfig({
plugins: [
nette({
entry: [
'app.js', // öffentliche Seiten
'admin.js', // Adminbereich
],
}),
],
});
Verwenden Sie sie in verschiedenen Templates:
{* Auf den öffentlichen Seiten *}
{asset 'app.js'}
{* Im Adminbereich *}
{asset 'admin.js'}
Wichtig: Quell- vs. kompilierte Dateien
Es ist entscheidend zu verstehen, dass Sie in der Produktion nur Dateien laden können, die Vite bereitstellt – entweder über sein Manifest oder indem sie unverändert aus dem Public-Ordner kopiert werden:
- Einstiegspunkte, die in
entrydefiniert sind (einschließlich der Module, die sie dynamisch importieren), und Assets, auf die aus JavaScript oder CSS verwiesen wird (Bilder, Schriften, …) – all das wird im Manifest festgehalten - Dateien aus dem Verzeichnis
assets/public/– diese stehen nicht im Manifest; sie werden unverändert kopiert, und{asset}findet sie über einen Fallback im Dateisystem
Sie können mit {asset} keine beliebigen Dateien aus assets/ laden – wird eine Datei
nirgends referenziert, wird sie nicht kompiliert. Wenn Sie Vite weitere Assets bekannt machen wollen, können Sie sie in den Public-Ordner verschieben.
Beachten Sie, dass Vite standardmäßig alle Assets kleiner als 4 KB inline einbettet, sodass Sie diese Dateien nicht direkt referenzieren können. (Siehe die Vite-Dokumentation).
{* ✓ Das funktioniert - es ist ein Einstiegspunkt *}
{asset 'app.js'}
{* ✓ Das funktioniert - es liegt in assets/public/ *}
{asset 'favicon.ico'}
{* ✗ Das funktioniert nicht - eine beliebige Datei in assets/ *}
{asset 'components/button.js'}
Entwicklungsmodus
Der Entwicklungsmodus ist völlig optional, bringt aber deutliche Vorteile, wenn er aktiviert ist. Der Hauptvorteil ist Hot Module Replacement (HMR) – Sie sehen Änderungen sofort, ohne den Zustand der Anwendung zu verlieren, was die Entwicklung deutlich flüssiger und schneller macht.
Vite ist ein modernes Build-Werkzeug, das die Entwicklung unglaublich schnell macht. Anders als klassische Bundler liefert Vite Ihren Code während der Entwicklung direkt an den Browser aus, was einen sofortigen Serverstart unabhängig von der Größe Ihres Projekts und blitzschnelle Aktualisierungen bedeutet.
Entwicklungsserver starten
Starten Sie den Entwicklungsserver:
npm run dev
Sie sehen:
➜ Local: http://localhost:5173/
➜ Network: use --host to expose
Lassen Sie dieses Terminal während der Entwicklung offen.
Solange der Dev-Server läuft, schreibt das Plugin eine kleine Signaldatei www/assets/.vite/nette.json mit seiner
URL. Nette Assets liest diese Datei auf der PHP-Seite und schaltet auf das Laden vom Dev-Server um, wenn beides zutrifft:
- der Vite-Dev-Server läuft (die Signaldatei existiert) und
- Ihre Nette-Anwendung ist im Debug-Modus.
Das Ergebnis:
{asset 'app.js'}
{* In der Entwicklung: <script src="http://localhost:5173/@vite/client" type="module"></script>
<script src="http://localhost:5173/app.js" type="module"></script> *}
{* In der Produktion: <script src="/assets/app-4f3a2b1c.js" type="module" crossorigin></script> *}
Keine Konfiguration nötig – es funktioniert einfach! Um die Erkennung abzuschalten oder die URL des Dev-Servers von Hand zu setzen, siehe die Option devServer.
Die Signaldatei liegt unter www/assets/.vite/nette.json (direkt neben der manifest.json
der Produktion). Sie können sie mit der Plugin-Option infoFile umbenennen, deren Standardwert
.vite/nette.json ist. Erkennt Nette den laufenden Dev-Server nicht, prüfen Sie, ob diese Datei existiert und auf die
richtige URL zeigt.
Arbeiten auf verschiedenen Domains
Läuft Ihr Entwicklungsserver auf etwas anderem als localhost (etwa myapp.local), können Probleme
mit CORS (Cross-Origin Resource Sharing) auftreten. CORS ist eine Sicherheitsfunktion in Webbrowsern, die Requests zwischen
verschiedenen Domains standardmäßig blockiert. Läuft Ihre PHP-Anwendung auf myapp.local, Vite aber auf
localhost:5173, sieht der Browser das als verschiedene Domains und blockiert die Requests.
Sie haben zwei Möglichkeiten, das zu lösen:
Möglichkeit 1: CORS konfigurieren
Am einfachsten erlauben Sie Cross-Origin-Requests aus Ihrer PHP-Anwendung:
export default defineConfig({
// ... weitere Konfiguration ...
server: {
cors: {
origin: 'http://myapp.local', // die URL Ihrer PHP-Anwendung
},
},
});
Möglichkeit 2: Vite auf Ihrer Domain laufen lassen
Die andere Lösung ist, Vite auf derselben Domain laufen zu lassen wie Ihre PHP-Anwendung.
export default defineConfig({
// ... weitere Konfiguration ...
server: {
host: 'myapp.local', // dieselbe wie bei Ihrer PHP-Anwendung
},
});
Tatsächlich müssen Sie auch in diesem Fall CORS konfigurieren, weil der Dev-Server unter demselben Hostnamen, aber auf einem anderen Port läuft. In diesem Fall konfiguriert das Nette-Vite-Plugin CORS jedoch automatisch.
HTTPS-Entwicklung
Wenn Sie über HTTPS entwickeln, brauchen Sie Zertifikate für Ihren Vite-Entwicklungsserver. Am einfachsten ist ein Plugin, das die Zertifikate automatisch erzeugt:
npm install -D vite-plugin-mkcert
So konfigurieren Sie es in vite.config.ts:
import mkcert from 'vite-plugin-mkcert';
export default defineConfig({
// ... weitere Konfiguration ...
plugins: [
mkcert(), // erzeugt die Zertifikate automatisch und aktiviert https
nette(),
],
});
Beachten Sie, dass Sie bei Verwendung der CORS-Konfiguration (Möglichkeit 1 von oben) die Origin-URL auf
https:// statt http:// anpassen müssen.
Entwicklung mit Docker
Wenn Sie Vite in einem Docker-Container laufen lassen, brauchen zwei Dinge Aufmerksamkeit: Der Browser auf Ihrem Rechner muss den Dev-Server erreichen können, und Vite muss Dateiänderungen über die Containergrenze hinweg erkennen.
Veröffentlichen Sie zuerst den Vite-Port aus dem Container und binden Sie den Dev-Server an alle Interfaces, damit er von außerhalb des Containers erreichbar ist:
export default defineConfig({
// ... weitere Konfiguration ...
plugins: [
nette(),
],
server: {
host: '0.0.0.0', // auf allen Interfaces lauschen (im Container nötig)
port: 5173, // muss zum veröffentlichten Port passen
strictPort: true, // lieber fehlschlagen als einen anderen Port wählen
watch: {
usePolling: true, // aktivieren, wenn Dateiänderungen auf gemounteten Volumes nicht erkannt werden
},
},
});
Das Plugin schreibt die URL des Dev-Servers für die PHP-Seite in die nette.json. Weil
host: '0.0.0.0' für einen Browser nicht nutzbar ist (er leitet bei jedem Asset auf localhost weiter),
schreibt das Plugin sie in dieser URL automatisch auf localhost um, damit die Assets korrekt geladen werden.
Wenn Sie die Anwendung statt unter localhost unter einer eigenen Domain öffnen, setzen Sie die Plugin-Option
host auf diese Domain:
plugins: [
nette({ host: 'myapp.local' }), // dieselbe Domain wie Ihre PHP-Anwendung
],
Das Plugin verwendet diesen Host dann für die URL des Dev-Servers, ergänzt ihn bei den CORS-Origins und trägt ihn in die
allowedHosts von Vite ein – so funktioniert es ohne jede manuelle CORS-Einrichtung.
Für komplexere Aufbauten – etwa wenn Vite hinter einem Reverse Proxy läuft, bei dem sich öffentlicher Host, Port und
Protokoll allesamt von der internen Adresse unterscheiden – setzen Sie Vites server.origin auf die vollständige
öffentliche URL. Das Plugin berücksichtigt sie und schreibt sie unverändert in die nette.json, statt die URL aus
dem lokalen Socket abzuleiten:
server: {
origin: 'https://myapp.local:8443', // die öffentliche URL, unter der der Browser Vite erreicht
},
Produktions-Builds
Erzeugen Sie optimierte Produktionsdateien:
npm run build
Vite wird:
- das gesamte JavaScript und CSS minifizieren
- den Code in optimale Chunks aufteilen
- gehashte Dateinamen fürs Cache Busting erzeugen
- eine Manifest-Datei für Nette Assets anlegen
Beispielausgabe:
www/assets/
├── app-4f3a2b1c.js # Ihr Haupt-JavaScript (minifiziert)
├── app-7d8e9f2a.css # extrahiertes CSS (minifiziert)
├── vendor-8c4b5e6d.js # gemeinsame Abhängigkeiten
└── .vite/
└── manifest.json # Zuordnung für Nette Assets
Die gehashten Dateinamen sorgen dafür, dass Browser immer die neueste Version laden.
Public-Ordner
Dateien im Verzeichnis assets/public/ werden ohne Verarbeitung in die Ausgabe kopiert:
assets/
├── public/
│ ├── favicon.ico
│ ├── robots.txt
│ └── images/
│ └── og-image.jpg
├── app.js
└── style.css
Referenzieren Sie sie ganz normal:
{* Diese Dateien werden unverändert kopiert *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>
Für öffentliche Dateien können Sie die Möglichkeiten des FilesystemMapper nutzen. Die Option extension gilt
für Referenzen ohne Endung (z. B. {asset 'images/og-image'} findet zuerst og-image.webp):
assets:
mapping:
default:
type: vite
path: assets
extension: [webp, jpg, png] # für Referenzen ohne Endung
versioning: true # Cache Busting ergänzen
In der Konfiguration vite.config.ts können Sie den Public-Ordner über die Option publicDir
ändern.
Dynamische Importe
Vite teilt den Code automatisch für optimales Laden auf. Dynamische Importe erlauben es, Code erst dann zu laden, wenn er wirklich gebraucht wird, was die Größe des anfänglichen Bundles verringert:
// Schwere Komponenten bei Bedarf laden
button.addEventListener('click', async () => {
let { Chart } = await import('./components/chart.js')
new Chart(data)
})
Dynamische Importe erzeugen eigene Chunks, die nur bei Bedarf geladen werden. Das nennt man “Code Splitting” und es ist eine der stärksten Funktionen von Vite. Wenn Sie dynamische Importe verwenden, erzeugt Vite für jedes dynamisch importierte Modul automatisch eine eigene JavaScript-Datei.
Der Tag {asset 'app.js'} lädt diese dynamischen Chunks nicht automatisch vor. Das ist beabsichtigt –
wir wollen keinen Code herunterladen, der vielleicht nie verwendet wird. Die Chunks werden erst heruntergeladen, wenn der
dynamische Import ausgeführt wird.
Wenn Sie jedoch wissen, dass bestimmte dynamische Importe entscheidend sind und bald gebraucht werden, können Sie sie vorladen:
{* Haupt-Einstiegspunkt *}
{asset 'app.js'}
{* Kritische dynamische Importe vorladen *}
{preload 'components/chart.js'}
Das sagt dem Browser, dass er die Chart-Komponente im Hintergrund herunterladen soll, damit sie bei Bedarf sofort bereitsteht.
TypeScript-Unterstützung
TypeScript funktioniert sofort:
// assets/main.ts
interface User {
name: string
email: string
}
export function greetUser(user: User): void {
console.log(`Hello, ${user.name}!`)
}
Referenzieren Sie TypeScript-Dateien ganz normal (wie bei jeder Datei muss main.ts ein Einstiegspunkt sein):
{asset 'main.ts'}
Für die volle TypeScript-Unterstützung installieren Sie es:
npm install -D typescript
Zusätzliche Vite-Konfiguration
Hier einige nützliche Konfigurationsoptionen von Vite mit ausführlichen Erklärungen:
export default defineConfig({
// Wurzelverzeichnis mit den Quell-Assets
root: 'assets',
// Ordner, dessen Inhalt unverändert in das Ausgabeverzeichnis kopiert wird
// Standard: 'public' (relativ zu 'root')
publicDir: 'public',
build: {
// Wohin die kompilierten Dateien kommen (relativ zu 'root')
outDir: '../www/assets',
// Ausgabeverzeichnis vor dem Build leeren?
// Nützlich, um alte Dateien früherer Builds zu entfernen
emptyOutDir: true,
// Unterverzeichnis innerhalb von outDir für erzeugte Chunks und Assets
// Das hilft, die Struktur der Ausgabe zu ordnen
assetsDir: 'static',
rollupOptions: {
// Einstiegspunkt(e) - eine einzelne Datei oder ein Array von Dateien
// Jeder Einstiegspunkt wird ein eigenes Bundle
input: [
'app.js', // Hauptanwendung
'admin.js', // Adminbereich
],
},
},
server: {
// Host, an den der Dev-Server gebunden wird
// '0.0.0.0' verwenden, um ihn im Netzwerk verfügbar zu machen
host: 'localhost',
// Port für den Dev-Server
port: 5173,
// CORS-Konfiguration für Cross-Origin-Requests
cors: {
origin: 'http://myapp.local',
},
},
css: {
// CSS-Sourcemaps in der Entwicklung aktivieren
devSourcemap: true,
},
plugins: [
nette(),
],
});
Achten Sie auf die Pfade der Einstiegspunkte in rollupOptions.input oben: Rollup löst relative
Pfade gegen das aktuelle Arbeitsverzeichnis auf (das Wurzelverzeichnis Ihres Projekts), nicht gegen
root: 'assets'. Ein bloßes 'app.js' existiert zur Build-Zeit also nicht. Verwenden Sie entweder die
Plugin-Option entry (die die Pfade der Einstiegspunkte relativ zu root auflöst) oder schreiben Sie die
Pfade relativ zum Wurzelverzeichnis des Projekts, also z. B. 'assets/app.js'.
Das war's! Sie haben nun ein modernes Build-System, das mit Nette Assets zusammenarbeitet.