Vite Entegrasyonu

Modern JavaScript uygulamaları gelişmiş derleme araçları gerektirir. Nette Assets, yeni nesil frontend derleme aracı Vite ile birinci sınıf entegrasyon sunar. Hot Module Replacement (HMR) ile ışık hızında geliştirme ve sıfır yapılandırma derdiyle iyileştirilmiş üretim derlemeleri elde edin.

  • Sıfır yapılandırma – Vite ile PHP şablonları arasında otomatik köprü
  • Eksiksiz bağımlılık yönetimi – tek bir etiket tüm varlıkları üstlenir
  • Hot Module Replacement – anında JavaScript ve CSS güncellemeleri
  • İyileştirilmiş üretim derlemeleri – kod bölme ve tree shaking

Nette Assets, Vite ile kusursuz bütünleşir; böylece şablonlarınızı her zamanki gibi yazarken tüm bu avantajları elde edersiniz.

Vite'ı Kurma

Vite'ı adım adım kuralım. Derleme araçlarına yeniyseniz endişelenmeyin, her şeyi açıklayacağız!

Adım 1: Vite'ı kurun

Önce projenize Vite'ı ve Nette eklentisini kurun:

npm install -D vite @nette/vite-plugin

Bu, Vite'ı ve Vite'ın Nette ile kusursuz çalışmasına yardım eden özel bir eklentiyi kurar.

Adım 2: Proje yapısı

Standart yaklaşım, kaynak varlık dosyalarını projenizin kökündeki bir assets/ klasörüne, derlenmiş sürümleri ise www/assets/ içine koymaktır:

web-project/
├── assets/                   ← kaynak dosyalar (SCSS, TypeScript, kaynak görseller)
│   ├── public/               ← statik dosyalar (olduğu gibi kopyalanır)
│   │   └── favicon.ico
│   ├── images/
│   │   └── logo.png
│   ├── app.js                ← ana giriş noktası
│   └── style.css             ← stilleriniz
└── www/                      ← genel dizin (document root)
	├── assets/               ← derlenmiş dosyalar buraya gidecek
	└── index.php

assets/ klasörü kaynak dosyalarınızı, yani yazdığınız kodu içerir. Vite bu dosyaları işleyecek ve derlenmiş sürümleri www/assets/ içine koyacak.

Adım 3: Vite'ı yapılandırın

Proje kökünüzde bir vite.config.ts dosyası oluşturun. Bu dosya Vite'a kaynak dosyalarınızı nerede bulacağını ve derlenmişleri nereye koyacağını söyler.

Nette Vite eklentisi, yapılandırmayı basit kılan akıllı varsayılanlarla gelir. Frontend kaynak dosyalarınızın assets/ dizininde (root seçeneği), derlenmiş dosyaların ise www/assets/ içinde (outDir seçeneği) olduğunu varsayar. Yalnızca giriş noktasını belirtmeniz gerekir:

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

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

Kaputun altında eklenti, root ve outDir dışında her şeyin birbirine oturması için birkaç Vite seçeneğini daha ayarlar: base seçeneğini '' yapar (varlıklar doğrudan document root'tan sunulur), build.manifest seçeneğini true yapar (böylece Nette Assets hash'lenmiş dosya adlarını eşleyebilir) ve build.assetsDir seçeneğini '' yapar (derlenmiş dosyalar static/ alt klasörü olmadan doğrudan outDir içine iner). Bunların herhangi birini geçersiz kılabilirsiniz.

Varsayılan outDir (www/assets), www/ dizininin zaten var olmasını gerektirir. Yoksa eklenti “The output directory … does not exist” hatasıyla durur.

Varlıklarınızı derlemek için başka bir dizin adı belirtmek isterseniz, birkaç seçeneği değiştirmeniz gerekecek:

export default defineConfig({
	root: 'assets', // kaynak varlıkların kök dizini

	build: {
		outDir: '../www/assets',  // derlenmiş dosyaların gideceği yer
	},

	// ... diğer yapılandırma ...
});

outDir yolu root dizinine göreli sayılır; başındaki ../ bu yüzdendir.

Adım 4: Nette'i yapılandırın

common.neon dosyanızda Nette Assets'e Vite'tan söz edin:

assets:
	mapping:
		default:
			type: vite      # Nette'e ViteMapper kullanmasını söyler
			path: assets

Adım 5: Betikleri ekleyin

package.json dosyanıza şu betikleri ekleyin:

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

Artık şunları yapabilirsiniz:

  • npm run dev – hot reloading'li geliştirme sunucusunu başlatır
  • npm run build – iyileştirilmiş üretim dosyalarını oluşturur

Giriş Noktaları

Giriş noktası (entry point), uygulamanızın başladığı ana dosyadır. Bu dosyadan başka dosyaları (CSS, JavaScript modülleri, görseller) import edersiniz ve böylece bir bağımlılık ağacı oluşur. Vite bu import'ları izler ve her şeyi bir araya paketler.

Örnek giriş noktası assets/app.js:

// Stilleri import et
import './style.css'

// JavaScript modüllerini import et
import netteForms from 'nette-forms';
import naja from 'naja';

// Uygulamanı başlat
netteForms.initOnLoad();
naja.initialize();

Şablonda bir giriş noktasını şöyle ekleyebilirsiniz:

{asset 'app.js'}

Nette Assets gereken tüm HTML etiketlerini otomatik üretir: JavaScript, CSS ve diğer bağımlılıklar.

Birden Çok Giriş Noktası

Daha büyük uygulamalar sıklıkla ayrı giriş noktalarına gereksinim duyar:

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // genel sayfalar
				'admin.js',    // yönetim paneli
			],
		}),
	],
});

Onları farklı şablonlarda kullanın:

{* Genel sayfalarda *}
{asset 'app.js'}

{* Yönetim panelinde *}
{asset 'admin.js'}

Önemli: Kaynak Dosyalar ile Derlenmiş Dosyalar

Üretimde yalnızca Vite'ın kullanılabilir kıldığı dosyaları yükleyebileceğinizi anlamak çok önemlidir; bu ya manifest aracılığıyla ya da onları public klasöründen değiştirmeden kopyalayarak olur:

  1. entry içinde tanımlı giriş noktaları (dinamik olarak import ettikleri modüller dahil) ve JavaScript'ten ya da CSS'ten başvurulan varlıklar (görseller, yazı tipleri, …) – bunların hepsi manifest'e kaydedilir
  2. assets/public/ dizinindeki dosyalar – bunlar manifest'te değildir; olduğu gibi kopyalanırlar ve {asset} onları bir dosya sistemi yedeğiyle bulur

assets/ içindeki rastgele dosyaları {asset} ile yükleyemezsiniz; bir dosyaya hiçbir yerden başvurulmuyorsa derlenmez. Vite'ın başka varlıklardan haberdar olmasını istiyorsanız, onları public klasörüne taşıyabilirsiniz.

Vite'ın varsayılan olarak 4 KB'den küçük tüm varlıkları satır içine alacağını, dolayısıyla bu dosyalara doğrudan başvuramayacağınızı unutmayın. (Bkz. Vite belgeleri).

{* ✓ Bu çalışır - bir giriş noktası *}
{asset 'app.js'}

{* ✓ Bu çalışır - assets/public/ içinde *}
{asset 'favicon.ico'}

{* ✗ Bu çalışmaz - assets/ içinde rastgele bir dosya *}
{asset 'components/button.js'}

Geliştirme Kipi

Geliştirme kipi tümüyle isteğe bağlıdır, ama etkinleştirildiğinde belirgin avantajlar sağlar. Ana avantajı Hot Module Replacement (HMR): uygulama durumunu yitirmeden değişiklikleri anında görürsünüz; bu da geliştirme deneyimini çok daha akıcı ve hızlı kılar.

Vite, geliştirmeyi inanılmaz hızlı kılan modern bir derleme aracıdır. Geleneksel paketleyicilerin tersine Vite, geliştirme sırasında kodunuzu doğrudan tarayıcıya sunar; bu da projeniz ne kadar büyük olursa olsun anında sunucu başlangıcı ve ışık hızında güncellemeler demektir.

Geliştirme Sunucusunu Başlatma

Geliştirme sunucusunu çalıştırın:

npm run dev

Şunu göreceksiniz:

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

Geliştirme yaparken bu terminali açık tutun.

Dev sunucusu çalışırken eklenti, URL'sini içeren küçük bir sinyal dosyası olan www/assets/.vite/nette.json dosyasını yazar. PHP tarafındaki Nette Assets bu dosyayı okur ve şu iki koşul birlikte sağlandığında dev sunucusundan yüklemeye geçer:

  1. Vite dev sunucusu çalışıyor (sinyal dosyası var) ve
  2. Nette uygulamanız hata ayıklama kipinde.

Sonuç:

{asset 'app.js'}
{* Geliştirmede: <script src="http://localhost:5173/@vite/client" type="module"></script>
                 <script src="http://localhost:5173/app.js" type="module"></script> *}
{* Üretimde: <script src="/assets/app-4f3a2b1c.js" type="module" crossorigin></script> *}

Hiçbir yapılandırma gerekmez, öylece çalışır! Algılamayı kapatmak ya da dev sunucusu URL'sini elle ayarlamak için devServer seçeneğine bakın.

Sinyal dosyası www/assets/.vite/nette.json konumundadır (üretimdeki manifest.json dosyasının hemen yanında). Onu, varsayılanı .vite/nette.json olan eklentinin infoFile seçeneğiyle yeniden adlandırabilirsiniz. Nette çalışan dev sunucusunu yakalamıyorsa, bu dosyanın var olduğunu ve doğru URL'ye işaret ettiğini denetleyin.

Farklı Alan Adlarında Çalışma

Geliştirme sunucunuz localhost dışında bir yerde çalışıyorsa (örneğin myapp.local), CORS (Cross-Origin Resource Sharing) sorunlarıyla karşılaşabilirsiniz. CORS, web tarayıcılarında varsayılan olarak farklı alan adları arasındaki istekleri engelleyen bir güvenlik özelliğidir. PHP uygulamanız myapp.local üzerinde, Vite ise localhost:5173 üzerinde çalışırken, tarayıcı bunları farklı alan adları olarak görür ve istekleri engeller.

Bunu çözmek için iki seçeneğiniz var:

Seçenek 1: CORS'u yapılandırın

En basit çözüm, PHP uygulamanızdan gelen çapraz kaynak isteklerine izin vermektir:

export default defineConfig({
	// ... diğer yapılandırma ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // PHP uygulamanızın URL'si
		},
	},
});

Seçenek 2: Vite'ı kendi alan adınızda çalıştırın

Diğer çözüm, Vite'ı PHP uygulamanızla aynı alan adında çalıştırmaktır.

export default defineConfig({
	// ... diğer yapılandırma ...

	server: {
		host: 'myapp.local',  // PHP uygulamanızla aynı
	},
});

Aslında bu durumda da CORS'u yapılandırmanız gerekir, çünkü dev sunucusu aynı hostname'de ama farklı bir portta çalışır. Ancak bu durumda CORS, Nette Vite eklentisi tarafından otomatik yapılandırılır.

HTTPS ile Geliştirme

HTTPS üzerinde geliştiriyorsanız, Vite geliştirme sunucunuz için sertifikalara gereksinim duyarsınız. En kolay yol, sertifikaları otomatik üreten bir eklenti kullanmaktır:

npm install -D vite-plugin-mkcert

Onu vite.config.ts içinde şöyle yapılandırırsınız:

import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... diğer yapılandırma ...

	plugins: [
		mkcert(),  // sertifikaları otomatik üretir ve https'i etkinleştirir
		nette(),
	],
});

CORS yapılandırmasını (yukarıdaki Seçenek 1) kullanıyorsanız, origin URL'sini http:// yerine https:// kullanacak biçimde güncellemeniz gerektiğini unutmayın.

Docker ile Geliştirme

Vite'ı bir Docker konteynerinin içinde çalıştırdığınızda iki şeye dikkat etmek gerekir: makinenizdeki tarayıcının dev sunucusuna ulaşabilmesi ve Vite'ın konteyner sınırının ötesindeki dosya değişikliklerini algılayabilmesi.

Önce Vite portunu konteynerden yayımlayın ve dev sunucusunu tüm arayüzlere bağlayın; böylece konteynerin dışından erişilebilir olur:

export default defineConfig({
	// ... diğer yapılandırma ...

	plugins: [
		nette(),
	],
	server: {
		host: '0.0.0.0',      // tüm arayüzleri dinle (konteynerde gereklidir)
		port: 5173,           // yayımlanan portla eşleşmelidir
		strictPort: true,     // başka bir port seçmek yerine başarısız ol
		watch: {
			usePolling: true, // bağlı birimlerde dosya değişiklikleri algılanmıyorsa etkinleştir
		},
	},
});

Eklenti, dev sunucusu URL'sini PHP tarafı için nette.json içine yazar. host: '0.0.0.0' bir tarayıcı tarafından kullanılamayacağından (her varlık için localhost adresine yönlendirir), eklenti onu bu URL'de otomatik olarak localhost biçimine yeniden yazar; böylece varlıklar doğru yüklenir.

Uygulamayı localhost yerine özel bir alan adında açıyorsanız, eklentinin host seçeneğini o alan adına ayarlayın:

	plugins: [
		nette({ host: 'myapp.local' }),  // PHP uygulamanızla aynı alan adı
	],

Eklenti bu host'u dev sunucusu URL'si için kullanır, onu CORS origin'lerine ekler ve Vite'ın allowedHosts listesine alır; böylece elle CORS ayarı yapmadan çalışır.

Daha karmaşık kurulumlar için, örneğin Vite'ın; genel host, port ve protokolün iç adresten ayrıldığı bir ters vekil sunucunun arkasında çalıştığı durumlarda, Vite'ın server.origin seçeneğini tam genel URL'ye ayarlayın. Eklenti buna saygı gösterir ve URL'yi yerel soketten türetmek yerine olduğu gibi nette.json içine yazar:

	server: {
		origin: 'https://myapp.local:8443',  // tarayıcının Vite'a ulaştığı genel URL
	},

Üretim Derlemeleri

İyileştirilmiş üretim dosyalarını oluşturun:

npm run build

Vite şunları yapacak:

  • Tüm JavaScript ve CSS'i küçültür
  • Kodu en uygun parçalara böler
  • Önbellek geçersizleştirme için hash'lenmiş dosya adları üretir
  • Nette Assets için bir manifest dosyası oluşturur

Örnek çıktı:

www/assets/
├── app-4f3a2b1c.js       # Ana JavaScript'iniz (küçültülmüş)
├── app-7d8e9f2a.css      # Ayıklanmış CSS (küçültülmüş)
├── vendor-8c4b5e6d.js    # Paylaşılan bağımlılıklar
└── .vite/
	└── manifest.json     # Nette Assets için eşleme

Hash'lenmiş dosya adları, tarayıcıların her zaman en son sürümü yüklemesini sağlar.

Public Klasörü

assets/public/ dizinindeki dosyalar, işlenmeden çıktıya kopyalanır:

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

Onlara normal biçimde başvurun:

{* Bu dosyalar olduğu gibi kopyalanır *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

Public dosyalar için FilesystemMapper özelliklerini kullanabilirsiniz. extension seçeneği, uzantısız başvurular için geçerlidir (örneğin {asset 'images/og-image'} önce og-image.webp dosyasını bulur):

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # uzantısız başvurular için
			versioning: true             # Önbellek geçersizleştirme ekle

vite.config.ts yapılandırmasında public klasörünü publicDir seçeneğiyle değiştirebilirsiniz.

Dinamik Import'lar

Vite, en uygun yükleme için kodu otomatik böler. Dinamik import'lar, kodu yalnızca gerçekten gerektiğinde yüklemenizi sağlar ve başlangıç paket boyutunu küçültür:

// Ağır bileşenleri istendiğinde yükle
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

Dinamik import'lar, yalnızca gerektiğinde yüklenen ayrı parçalar oluşturur. Buna “kod bölme” denir ve Vite'ın en güçlü özelliklerinden biridir. Dinamik import kullandığınızda, Vite dinamik olarak import edilen her modül için otomatik olarak ayrı JavaScript dosyaları oluşturur.

{asset 'app.js'} etiketi bu dinamik parçaları otomatik olarak önceden yüklemez. Bu kasıtlı bir davranıştır; hiç kullanılmayabilecek kodu indirmek istemeyiz. Parçalar yalnızca dinamik import çalıştırıldığında indirilir.

Ancak belirli dinamik import'ların kritik olduğunu ve yakında gerekeceğini biliyorsanız, onları önceden yükleyebilirsiniz:

{* Ana giriş noktası *}
{asset 'app.js'}

{* Kritik dinamik import'ları önceden yükle *}
{preload 'components/chart.js'}

Bu, tarayıcıya chart bileşenini arka planda indirmesini söyler; böylece gerektiğinde hemen hazır olur.

TypeScript Desteği

TypeScript kutudan çıktığı gibi çalışır:

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

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

TypeScript dosyalarına normal biçimde başvurun (her dosyada olduğu gibi, main.ts bir giriş noktası olmalıdır):

{asset 'main.ts'}

Tam TypeScript desteği için onu kurun:

npm install -D typescript

Ek Vite Yapılandırması

İşte ayrıntılı açıklamalarıyla birlikte bazı yararlı Vite yapılandırma seçenekleri:

export default defineConfig({
	// Kaynak varlıkları içeren kök dizin
	root: 'assets',

	// İçeriği çıktı dizinine olduğu gibi kopyalanan klasör
	// Varsayılan: 'public' ('root' dizinine göreli)
	publicDir: 'public',

	build: {
		// Derlenmiş dosyaların konacağı yer ('root' dizinine göreli)
		outDir: '../www/assets',

		// Derlemeden önce çıktı dizini boşaltılsın mı?
		// Önceki derlemelerden kalan eski dosyaları kaldırmak için yararlıdır
		emptyOutDir: true,

		// Üretilen parçalar ve varlıklar için outDir içindeki alt dizin
		// Bu, çıktı yapısını düzenlemeye yardım eder
		assetsDir: 'static',

		rollupOptions: {
			// Giriş noktası/noktaları - tek bir dosya ya da dosya dizisi olabilir
			// Her giriş noktası ayrı bir paket olur
			input: [
				'app.js',      // ana uygulama
				'admin.js',    // yönetim paneli
			],
		},
	},

	server: {
		// Dev sunucusunun bağlanacağı host
		// Ağa açmak için '0.0.0.0' kullanın
		host: 'localhost',

		// Dev sunucusunun portu
		port: 5173,

		// Çapraz kaynak istekleri için CORS yapılandırması
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Geliştirmede CSS source map'leri etkinleştir
		devSourcemap: true,
	},

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

Yukarıdaki rollupOptions.input içindeki giriş yollarına dikkat edin: Rollup göreli yolları, root: 'assets' dizinine değil, geçerli çalışma dizinine (proje kökünüze) göre çözer. Dolayısıyla yalın bir 'app.js' derleme zamanında var olmayacak. Ya eklentinin entry seçeneğini kullanın (o, giriş yollarını root dizinine göreli çözer) ya da yolları proje köküne göreli yazın, örneğin 'assets/app.js'.

Hepsi bu! Artık Nette Assets ile bütünleşik modern bir derleme sisteminiz var.

versiyon: 1.x