Integracja z Vite

Nowoczesne aplikacje JavaScript wymagają zaawansowanych narzędzi do budowania. Nette Assets zapewnia pierwszorzędną integrację z Vite, narzędziem do budowania frontendowego nowej generacji. Uzyskaj błyskawiczne środowisko deweloperskie z Hot Module Replacement (HMR) i zoptymalizowane kompilacje produkcyjne bez problemów z konfiguracją.

  • Zero konfiguracji – automatyczny most między Vite a szablonami PHP
  • Kompletne zarządzanie zależnościami – jeden tag obsługuje wszystkie zasoby
  • Hot Module Replacement – natychmiastowe aktualizacje JavaScript i CSS
  • Zoptymalizowane kompilacje produkcyjne – dzielenie kodu i tree shaking

Nette Assets integruje się bezproblemowo z Vite, dzięki czemu uzyskujesz wszystkie te korzyści, pisząc swoje szablony jak zwykle.

Konfigurowanie Vite

Skonfigurujmy Vite krok po kroku. Nie martw się, jeśli jesteś nowy w narzędziach do budowania – wyjaśnimy wszystko!

Krok 1: Zainstaluj Vite

Najpierw zainstaluj Vite i wtyczkę Nette w swoim projekcie:

npm install -D vite @nette/vite-plugin

To instaluje Vite i specjalną wtyczkę, która pomaga Vite doskonale współpracować z Nette.

Krok 2: Struktura projektu

Standardowe podejście to umieszczenie plików źródłowych zasobów w folderze assets/ w katalogu głównym projektu, a skompilowanych wersji w www/assets/:

web-project/
├── assets/                   ← pliki źródłowe (SCSS, TypeScript, obrazy źródłowe)
│   ├── public/               ← pliki statyczne (kopiowane bez zmian)
│   │   └── favicon.ico
│   ├── images/
│   │   └── logo.png
│   ├── app.js                ← główny punkt wejścia
│   └── style.css             ← Twoje style
└── www/                      ← katalog publiczny (root dokumentu)
	├── assets/               ← tutaj trafią skompilowane pliki
	└── index.php

Folder assets/ zawiera Twoje pliki źródłowe – kod, który piszesz. Vite przetworzy te pliki i umieści skompilowane wersje w www/assets/.

Krok 3: Skonfiguruj Vite

Utwórz plik vite.config.ts w katalogu głównym projektu. Ten plik informuje Vite, gdzie znaleźć Twoje pliki źródłowe i gdzie umieścić skompilowane.

Wtyczka Nette Vite ma inteligentne wartości domyślne, które upraszczają konfigurację. Zakłada, że Twoje pliki źródłowe front-end znajdują się w katalogu assets/ (opcja root), a skompilowane pliki trafiają do www/assets/ (opcja outDir). Musisz tylko określić punkt wejścia:

import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';

export default defineConfig({
	plugins: [
		nette({
			entry: 'app.js',
		}),
	],
});

Jeśli chcesz określić inną nazwę katalogu do budowania swoich zasobów, będziesz musiał zmienić kilka opcji:

export default defineConfig({
	root: 'assets', // katalog główny zasobów źródłowych

	build: {
		outDir: '../www/assets',  // gdzie trafiają skompilowane pliki
	},

	// ... inna konfiguracja ...
});

Ścieżka outDir jest traktowana jako względna do root, dlatego na początku znajduje się ../.

Krok 4: Skonfiguruj Nette

Poinformuj Nette Assets o Vite w swoim common.neon:

assets:
	mapping:
		default:
			type: vite      # informuje Nette, aby użyło ViteMapper
			path: assets

Krok 5: Dodaj skrypty

Dodaj te skrypty do swojego package.json:

{
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	}
}

Teraz możesz:

  • npm run dev – uruchom serwer deweloperski z hot reloadingiem
  • npm run build – utwórz zoptymalizowane pliki produkcyjne

Punkty wejścia

Punkt wejścia to główny plik, w którym uruchamia się Twoja aplikacja. Z tego pliku importujesz inne pliki (CSS, moduły JavaScript, obrazy), tworząc drzewo zależności. Vite śledzi te importy i łączy wszystko razem.

Przykładowy punkt wejścia assets/app.js:

// Importuj style
import './style.css'

// Importuj moduły JavaScript
import netteForms from 'nette-forms';
import naja from 'naja';

// Zainicjuj swoją aplikację
netteForms.initOnLoad();
naja.initialize();

W szablonie możesz wstawić punkt wejścia w następujący sposób:

{asset 'app.js'}

Nette Assets automatycznie generuje wszystkie niezbędne tagi HTML – JavaScript, CSS i wszelkie inne zależności.

Wiele punktów wejścia

Większe aplikacje często potrzebują oddzielnych punktów wejścia:

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // strony publiczne
				'admin.js',    // panel administracyjny
			],
		}),
	],
});

Używaj ich w różnych szablonach:

{* Na stronach publicznych *}
{asset 'app.js'}

{* W panelu administracyjnym *}
{asset 'admin.js'}

Ważne: Pliki źródłowe vs skompilowane

Kluczowe jest zrozumienie, że w środowisku produkcyjnym możesz ładować tylko:

  1. Punkty wejścia zdefiniowane w entry
  2. Pliki z katalogu assets/public/

Nie możesz ładować za pomocą {asset} dowolnych plików z assets/ – tylko zasoby, do których odwołują się pliki JavaScript lub CSS. Jeśli Twój plik nie jest nigdzie odwołany, nie zostanie skompilowany. Jeśli chcesz, aby Vite był świadomy innych zasobów, możesz przenieść je do folderu publicznego.

Należy pamiętać, że domyślnie Vite wbuduje wszystkie zasoby mniejsze niż 4KB, więc nie będziesz mógł odwoływać się do tych plików bezpośrednio. (Zobacz dokumentację Vite).

{* ✓ To działa - to punkt wejścia *}
{asset 'app.js'}

{* ✓ To działa - to jest w assets/public/ *}
{asset 'favicon.ico'}

{* ✗ To nie zadziała - losowy plik w assets/ *}
{asset 'components/button.js'}

Tryb deweloperski

Tryb deweloperski jest całkowicie opcjonalny, ale zapewnia znaczące korzyści po włączeniu. Główną zaletą jest Hot Module Replacement (HMR) – natychmiastowe widzenie zmian bez utraty stanu aplikacji, co sprawia, że doświadczenie deweloperskie jest znacznie płynniejsze i szybsze.

Vite to nowoczesne narzędzie do budowania, które sprawia, że rozwój jest niewiarygodnie szybki. W przeciwieństwie do tradycyjnych bundlerów, Vite serwuje Twój kod bezpośrednio do przeglądarki podczas developmentu, co oznacza natychmiastowe uruchomienie serwera niezależnie od wielkości projektu i błyskawiczne aktualizacje.

Uruchamianie serwera deweloperskiego

Uruchom serwer deweloperski:

npm run dev

Zobaczysz:

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Pozostaw ten terminal otwarty podczas developmentu.

Wtyczka Nette Vite automatycznie wykrywa, kiedy:

  1. Serwer deweloperski Vite jest uruchomiony
  2. Twoja aplikacja Nette jest w trybie debugowania

Gdy oba warunki są spełnione, Nette Assets ładuje pliki z serwera deweloperskiego Vite zamiast z katalogu skompilowanego:

{asset 'app.js'}
{* W trybie deweloperskim: <script src="http://localhost:5173/app.js" type="module"></script> *}
{* W trybie produkcyjnym: <script src="/assets/app-4a8f9c7.js" type="module"></script> *}

Nie potrzeba konfiguracji – po prostu działa!

Praca na różnych domenach

Jeśli Twój serwer deweloperski działa na czymś innym niż localhost (np. myapp.local), możesz napotkać problemy z CORS (Cross-Origin Resource Sharing). CORS to funkcja bezpieczeństwa w przeglądarkach internetowych, która domyślnie blokuje żądania między różnymi domenami. Gdy Twoja aplikacja PHP działa na myapp.local, a Vite na localhost:5173, przeglądarka traktuje je jako różne domeny i blokuje żądania.

Masz dwie opcje rozwiązania tego problemu:

Opcja 1: Skonfiguruj CORS

Najprostszym rozwiązaniem jest zezwolenie na żądania cross-origin z Twojej aplikacji PHP:

export default defineConfig({
	// ... inna konfiguracja ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // URL Twojej aplikacji PHP
		},
	},
});

Opcja 2: Uruchom Vite na swojej domenie

Innym rozwiązaniem jest uruchomienie Vite na tej samej domenie co Twoja aplikacja PHP.

export default defineConfig({
	// ... inna konfiguracja ...

	server: {
		host: 'myapp.local',  // to samo co Twoja aplikacja PHP
	},
});

W rzeczywistości, nawet w tym przypadku, musisz skonfigurować CORS, ponieważ serwer deweloperski działa na tej samej nazwie hosta, ale na innym porcie. Jednak w tym przypadku CORS jest automatycznie konfigurowany przez wtyczkę Nette Vite.

Development HTTPS

Jeśli rozwijasz na HTTPS, potrzebujesz certyfikatów dla swojego serwera deweloperskiego Vite. Najprostszym sposobem jest użycie wtyczki, która automatycznie generuje certyfikaty:

npm install -D vite-plugin-mkcert

Oto jak skonfigurować to w vite.config.ts:

import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... inna konfiguracja ...

	plugins: [
		mkcert(),  // automatycznie generuje certyfikaty i włącza https
		nette(),
	],
});

Zauważ, że jeśli używasz konfiguracji CORS (Opcja 1 powyżej), musisz zaktualizować adres URL źródła, aby używał https:// zamiast http://.

Kompilacje produkcyjne

Utwórz zoptymalizowane pliki produkcyjne:

npm run build

Vite będzie:

  • Minifikować cały JavaScript i CSS
  • Dzielić kod na optymalne części
  • Generować nazwy plików z hashami dla unieważniania pamięci podręcznej
  • Tworzyć plik manifestu dla Nette Assets

Przykładowe wyjście:

www/assets/
├── app-4f3a2b1c.js       # Twój główny JavaScript (zminifikowany)
├── app-7d8e9f2a.css      # Wyodrębniony CSS (zminifikowany)
├── vendor-8c4b5e6d.js    # Wspólne zależności
└── .vite/
	└── manifest.json     # Mapowanie dla Nette Assets

Nazwy plików z hashami zapewniają, że przeglądarki zawsze ładują najnowszą wersję.

Folder publiczny

Pliki w katalogu assets/public/ są kopiowane do wyjścia bez przetwarzania:

assets/
├── public/
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
│       └── og-image.jpg
├── app.js
└── style.css

Odwołuj się do nich normalnie:

{* Te pliki są kopiowane bez zmian *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

Dla plików publicznych możesz użyć funkcji FilesystemMapper:

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # Spróbuj najpierw WebP
			versioning: true             # Dodaj unieważnianie pamięci podręcznej

W konfiguracji vite.config.ts możesz zmienić folder publiczny za pomocą opcji publicDir.

Dynamiczne importy

Vite automatycznie dzieli kod dla optymalnego ładowania. Dynamiczne importy pozwalają ładować kod tylko wtedy, gdy jest faktycznie potrzebny, zmniejszając początkowy rozmiar pakietu:

// Ładuj ciężkie komponenty na żądanie
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

Dynamiczne importy tworzą oddzielne części kodu, które są ładowane tylko wtedy, gdy są potrzebne. Nazywa się to “dzieleniem kodu” i jest to jedna z najpotężniejszych funkcji Vite. Kiedy używasz dynamicznych importów, Vite automatycznie tworzy oddzielne pliki JavaScript dla każdego dynamicznie importowanego modułu.

Tag {asset 'app.js'} nie ładuje automatycznie tych dynamicznych części kodu. Jest to zamierzone zachowanie – nie chcemy pobierać kodu, który może nigdy nie zostać użyty. Części kodu są pobierane tylko wtedy, gdy dynamiczny import jest wykonywany.

Jednakże, jeśli wiesz, że pewne dynamiczne importy są krytyczne i będą potrzebne wkrótce, możesz je wstępnie załadować:

{* Główny punkt wejścia *}
{asset 'app.js'}

{* Wstępnie załaduj krytyczne dynamiczne importy *}
{preload 'components/chart.js'}

To instruuje przeglądarkę, aby pobrała komponent wykresu w tle, dzięki czemu jest on natychmiast gotowy, gdy będzie potrzebny.

Obsługa TypeScript

TypeScript działa od razu po wyjęciu z pudełka:

// assets/main.ts
interface User {
	name: string
	email: string
}

export function greetUser(user: User): void {
	console.log(`Hello, ${user.name}!`)
}

Odwołuj się do plików TypeScript normalnie:

{asset 'main.ts'}

Dla pełnej obsługi TypeScript, zainstaluj go:

npm install -D typescript

Dodatkowa konfiguracja Vite

Oto kilka przydatnych opcji konfiguracyjnych Vite ze szczegółowymi wyjaśnieniami:

export default defineConfig({
	// Katalog główny zawierający zasoby źródłowe
	root: 'assets',

	// Folder, którego zawartość jest kopiowana do katalogu wyjściowego bez zmian
	// Domyślnie: 'public' (względnie do 'root')
	publicDir: 'public',

	build: {
		// Gdzie umieścić skompilowane pliki (względnie do 'root')
		outDir: '../www/assets',

		// Opróżnić katalog wyjściowy przed budowaniem?
		// Przydatne do usuwania starych plików z poprzednich kompilacji
		emptyOutDir: true,

		// Podkatalog w outDir dla generowanych części kodu i zasobów
		// Pomaga to zorganizować strukturę wyjściową
		assetsDir: 'static',

		rollupOptions: {
			// Punkt(y) wejścia - może być pojedynczym plikiem lub tablicą plików
			// Każdy punkt wejścia staje się oddzielnym pakietem
			input: [
				'app.js',      // główna aplikacja
				'admin.js',    // panel administracyjny
			],
		},
	},

	server: {
		// Host do powiązania serwera deweloperskiego
		// Użyj '0.0.0.0', aby udostępnić w sieci
		host: 'localhost',

		// Port dla serwera deweloperskiego
		port: 5173,

		// Konfiguracja CORS dla żądań cross-origin
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Włącz mapy źródłowe CSS w trybie deweloperskim
		devSourcemap: true,
	},

	plugins: [
		nette(),
	],
});

To wszystko! Masz teraz nowoczesny system budowania zintegrowany z Nette Assets.

wersja: 1.0