Vite , geliştiriciler arasında giderek daha popüler hale geliyor, ancak topluluk o kadar büyük olmadığından ( Webpack'teki gibi), sorunlarınızı çözmek için kendi özel eklentinizi oluşturmanız gerekebilir. Bu yazımızda Vite için nasıl eklenti oluşturulacağını tartışacağız ve kendi eklentimi parçalayacağım.
Bir eklenti oluşturmak için Vite'ın geliştirme sunucusu ( vite
komutu) ve paket ( vite build
) için farklı derleme sistemleri kullandığını bilmek önemlidir.
Geliştirme sunucusu için, modern tarayıcılar tarafından desteklenen yerel ES modüllerine sahip esbuild'i kullanıyor ve kodu tek bir dosyada toplamamıza gerek kalmıyor ve bu bize hızlı HRM (Sıcak Modül Değiştirme) sağlıyor.
Paket için rollup.js kullanıyor çünkü esnek ve geniş bir ekosisteme sahip; farklı çıktı formatlarıyla yüksek düzeyde optimize edilmiş üretim paketlerinin oluşturulmasına olanak tanır.
Vite'ın eklenti arayüzü Rollup'ınkine dayanmaktadır ancak geliştirme sunucusuyla çalışmak için ek seçenekler ve kancalar içerir.
Bir eklenti oluşturduğunuzda, onu vite.config.js
dosyanıza satır içi olarak yazabilirsiniz. Bunun için yeni bir paket oluşturmaya gerek yoktur. Bir eklentinin projelerinizde faydalı olduğunu gördüğünüzde onu toplulukla paylaşmayı ve Vite ekosistemine katkıda bulunmayı düşünün.
Ayrıca, rollup.js daha büyük bir topluluğa ve ekosisteme sahip olduğundan, rollup.js için bir eklenti oluşturmayı düşünebilirsiniz; bu, Vite'ta da aynı şekilde çalışacaktır. Yani eğer eklenti işlevselliğiniz sadece bundle için çalışıyorsa Vite yerine rollup.js eklentisini tercih edebilirsiniz ve kullanıcılar rollup eklentinizi Vite projelerinde sorunsuzca kullanabilirler.
Toplama için bir eklenti oluşturursanız yalnızca rollup.js kullanan daha fazla kullanıcıyı kapsayacaksınız. Eklentiniz geliştirme sunucusunu etkileyecekse Vite eklentisini tercih edin.
Doğrudan vite.config.ts
dosyasında eklenti oluşturmaya başlayalım:
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });
Bu örnekte, her iki aşamada da konsolda çözümlenir çözülmez Vite yapılandırmasını yazdıran myPlugin
adında bir eklenti oluşturdum: geliştirme sunucusu ve paket. Config'i yalnızca geliştirme sunucusu modunda yazdırmak istersem, bundle için apply: 'serve'
ve apply: 'build'
eklemeliyim.
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin { return { name: 'my-plugin', apply: 'serve', configResolved(config) { console.log(config); }, }; } export default defineConfig({ plugins: [ myPlugin(), ], });
Ayrıca bir dizi eklentiyi de iade edebilirim; geliştirme sunucusu ve paket için işlevleri ayırmak açısından kullanışlıdır:
// vite.config.ts import { defineConfig, Plugin } from 'vite'; function myPlugin(): Plugin[] { return [ { name: 'my-plugin:serve', apply: 'serve', configResolved(config) { console.log('dev server:', config); }, }, { name: 'my-plugin:build', apply: 'build', configResolved(config) { console.log('bundle:', config); }, }, ]; } export default defineConfig({ plugins: [ myPlugin(), ], });
Ve hemen hemen bu kadar; Vite yapılandırmasına kolayca küçük eklentiler ekleyebilirsiniz. Bir eklenti çok büyürse, onu başka bir dosyaya taşımayı, hatta bir paket oluşturmayı tercih ederim.
Daha karmaşık bir şeye ihtiyacınız varsa Vite'ın belgelerinde keşfedebileceğiniz birçok yararlı kanca vardır. Ancak örnek olarak aşağıda kendi eklentimi inceleyelim.
Simge dosyalarına dayalı SVG sprite'ları oluşturmak için bir eklentim var - vite-plugin-svg-spritemap .
Amaç, src/icons
klasöründeki tüm simgeleri .svg
almak ve içeriklerini SVG sprite adı verilen tek bir .svg
dosyasında toplamaktır. Paket aşamasından başlayalım:
import { Plugin, ResolvedConfig } from 'vite'; import path from 'path'; import fs from 'fs-extra'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: 'my-plugin:build', apply: 'build', async configResolved(_config) { config = _config; }, writeBundle() { const sprite = getSpriteContent({ pattern: 'src/icons/*.svg' }); const filePath = path.resolve(config.root, config.build.outDir, 'sprite.svg'); fs.ensureFileSync(filePath); fs.writeFileSync(filePath, sprite); }, }; }
Hook configResolved
sonraki kancalarda kullanmak üzere çözümlendiğinde config almamızı sağlar;
writeBundle
kancası paketleme işlemi bittikten sonra çağrılır ve burada sprite.svg
dosyasını oluşturacağım;
getSpriteContent
işlevi, src/icons/*.svg
desenine dayalı olarak hazırlanmış bir SVG sprite dizisi döndürür. Bu konuda daha derine inmeyeceğim; SVG sprite oluşturma sürecinin tamamını açıklayan diğer makaleme göz atabilirsiniz;
Daha sonra, path.resolve()
ile SVG hareketli grafik içeriğini yerleştirmek için sprite.svg
dosyasının mutlak yolunu oluşturuyorum, fs.ensureFileSync
ile dosyanın var olduğundan emin oluyorum (veya bir tane oluşturuyorum) ve SVG hareketli grafik içeriğini bu dosyaya yazıyorum. .
Şimdi en ilginç kısıma gelelim: geliştirici sunucusu aşamasına. Burada writeBundle
kullanamıyorum ve dev sunucusu çalışırken dosyaları barındıramıyorum, bu nedenle sprite.svg
isteğini yakalamak için sunucu ara yazılımını kullanmamız gerekiyor.
import { Plugin, ResolvedConfig } from 'vite'; function myPlugin(): Plugin { let config: ResolvedConfig; return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { // (1) return () => { server.middlewares.use(async (req, res, next) => { // (2) if (req.url !== '/sprite.svg') { return next(); // (3) } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { // (4) 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }
configureServer
, dev sunucusunu yapılandırmak için kullanılan bir kancadır. Vite'ın dahili ara yazılımı kurulmadan önce tetiklenir; benim durumumda, dahili ara katman yazılımından sonra özel ara katman yazılımı eklemem gerekiyor, bu yüzden bir işlev döndürüyorum;
Geliştirici sunucusuna gelen her isteği yakalamak amacıyla özel ara katman yazılımı eklemek için server.middlewares.use()
kullanıyorum. [localhost:3000/sprite.svg](http://localhost:3000/sprite.svg)
URL'sine sahip istekleri algılamasına ihtiyacım var, böylece dosya davranışını taklit edebilirim;
İstek URL'si /sprite.svg
değilse - sonraki ara yazılıma geçin (yani kontrolü zincirdeki bir sonraki işleyiciye geçirin);
Dosya içeriğini hazırlamak için getSpriteContent
sonucunu sprite
değişkenine koyuyorum ve yapılandırılmış başlıklarla (içerik türü ve 200 HTTP durumu) yanıt olarak gönderiyorum.
Sonuç olarak dosya davranışını simüle ettim.
Ancak src/icons
içindeki dosyalar değiştirilirse, silinirse veya eklenirse, getSpriteContent
aracılığıyla yeni hareketli grafik içeriği oluşturmak için sunucuyu yeniden başlatmalıyız; bunun için dosya izleme kütüphanesini kullanacağım - chokidar . Koda chokidar işleyicilerini ekleyelim:
import { Plugin, ResolvedConfig } from 'vite'; import chokidar from 'chokidar'; function myPlugin(): Plugin { let config: ResolvedConfig; let watcher: chokidar.FSWatcher; // Defined variable for chokidar instance. return { name: `my-plugin:serve`, apply: 'serve', async configResolved(_config) { config = _config; }, configureServer(server) { function reloadPage() { // Function that sends a signal to reload the server. server.ws.send({ type: 'full-reload', path: '*' }); } watcher = chokidar .watch('src/icons/*.svg', { // Watch src/icons/*.svg cwd: config.root, // Define project root path ignoreInitial: true, // Don't trigger chokidar on instantiation. }) .on('add', reloadPage) // Add listeners to add, modify, delete. .on('change', reloadPage) .on('unlink', reloadPage); return () => { server.middlewares.use(async (req, res, next) => { if (req.url !== '/sprite.svg') { return next(); } const sprite = getSpriteContent({ pattern, prefix, svgo, currentColor }); res.writeHead(200, { 'Content-Type': 'image/svg+xml, charset=utf-8', 'Cache-Control': 'no-cache', }); res.end(sprite); }); }; }, }; }
Gördüğünüz gibi eklenti oluşturma API'si aslında karmaşık değil. Görevlerinize uyacak Vite veya Rollup kancalarını bulmanız yeterli. Örneğimde, Rollup.js'den writeBundle
kullanıyorum (dediğim gibi, paketi oluşturmak için kullanılıyor) ve Rollup.js'nin yerel geliştirici sunucusu desteği olmadığı için Vite'tan configureServer
.
writeBundle
durumunda bu çok basitti; SVG sprite içeriğini aldık ve bir dosyaya koyduk. Geliştirici sunucusu durumunda, neden aynısını yapamadığım kafamı karıştırdı; Diğer yazarların eklentilerine baktım ve hepsi aynı şeyi yapıyor.
Bu nedenle, configureServer
kullanıyorum ve server
argümanı aracılığıyla, sprite.svg
isteğini engelleyerek dev sunucusuna gelen her isteği tetikleyen ara katman yazılımını ekliyorum.
Daha önce de belirttiğim gibi daha kullanışlı eklentiler oluşturmak için kancaları keşfetmeniz gerekiyor. Bunlar belgelerde ayrıntılı olarak açıklanmaktadır:
https://vitejs.dev/guide/api-plugin#universal-hooks
https://vitejs.dev/guide/api-plugin#vite-spec-hooks
Adlandırma açısından, Vite'ın eklentiler için bazı kuralları vardır, bu yüzden bitirmeden önce kontrol etsen iyi olur. İşte bazı önemli noktalar:
vite-plugin-
önekiyle benzersiz bir adı olmalıdır;
vite-plugin
anahtar sözcüğünü package.json dosyasına ekleyin;
vite-plugin-vue-
, vite-plugin-react-
, vite-plugin-svelte-
).Eklentinizi NPM'de yayınlamaya karar verirseniz bunu öneririm çünkü bilgi ve uzmanlık paylaşımı, BT topluluğunun temel ilkesidir ve kolektif büyümeyi destekler. Paketinizi nasıl yayınlayacağınızı ve koruyacağınızı öğrenmek için rehberime göz atın → NPM paketi oluşturmanın en kolay yolu .
Ayrıca eklentinizi vite'nin topluluk listesine - harika-vite - göndermenizi şiddetle tavsiye ederim. Birçok kişi orada en uygun eklentileri arıyor ve bu, Vite ekosistemine katkıda bulunmak için harika bir fırsat olacak! Eklentinizi buraya gönderme süreci basittir; yalnızca şartları karşıladığınızdan emin olun ve bir çekme isteği oluşturun. Terimlerin listesini burada bulabilirsiniz.
Genel olarak, Vite'a özel (toplama değil), açık kaynak olması ve iyi belgelere sahip olması gerekir. Eklentilerinizde iyi şanslar!