Vite 는 개발자들 사이에서 점점 더 인기를 얻고 있지만 커뮤니티가 Webpack 만큼 크지 않기 때문에 문제를 해결하려면 사용자 정의 플러그인을 직접 만들어야 할 수도 있습니다. 이 기사에서는 Vite 용 플러그인을 만드는 방법에 대해 설명하고 내 플러그인을 분석해 보겠습니다.
플러그인을 생성하려면 Vite가 개발 서버( vite
명령)와 번들( vite build
명령)에 대해 서로 다른 빌드 시스템을 사용한다는 것을 아는 것이 중요합니다.
개발 서버의 경우 최신 브라우저에서 지원되는 기본 ES 모듈과 함께 esbuild를 사용하며 코드를 단일 파일로 묶을 필요가 없으며 빠른 HRM(Hot Module replacement)을 제공합니다.
번들의 경우 유연하고 대규모 생태계가 있기 때문에 Rollup.js를 사용합니다. 이를 통해 다양한 출력 형식으로 고도로 최적화된 프로덕션 번들을 생성할 수 있습니다.
Vite의 플러그인 인터페이스는 Rollup을 기반으로 하지만 개발 서버 작업을 위한 추가 옵션과 후크가 있습니다.
플러그인을 생성할 때 vite.config.js
에 인라인할 수 있습니다. 이를 위해 새 패키지를 만들 필요가 없습니다. 플러그인이 프로젝트에 유용하다는 것을 알게 되면 이를 커뮤니티와 공유하고 Vite 생태계에 기여하는 것을 고려해 보세요.
또한, Rollup.js는 더 큰 커뮤니티와 생태계를 가지고 있으므로, Rollup.js용 플러그인을 만드는 것을 고려해 볼 수 있으며 Vite에서도 잘 작동할 것입니다. 따라서 플러그인 기능이 번들에 대해서만 작동하는 경우 Vite 대신 Rollup.js 플러그인을 사용할 수 있으며 사용자는 Vite 프로젝트에서 문제 없이 롤업 플러그인을 사용할 수 있습니다.
롤업용 플러그인을 만들면, Rollup.js만 사용하는 사용자가 더 많아지게 됩니다. 플러그인이 개발 서버에 영향을 미치는 경우 Vite 플러그인을 사용하세요.
vite.config.ts
에서 직접 플러그인 생성을 시작해 보겠습니다.
// 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(), ], });
이 예에서는 개발 서버와 번들이라는 두 단계의 콘솔에서 Vite 구성이 해결되는 즉시 Vite 구성을 인쇄하는 myPlugin
이라는 플러그인을 만들었습니다. 개발 서버 모드에서만 구성을 인쇄하려면 apply: 'serve'
추가하고 번들에 apply: 'build'
해야 합니다.
// 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(), ], });
또한 플러그인 배열을 반환할 수도 있습니다. 개발 서버와 번들의 기능을 분리하는 데 유용합니다.
// 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(), ], });
그리고 그게 거의 전부입니다. Vite 구성에 작은 플러그인을 쉽게 추가할 수 있습니다. 그리고 플러그인이 너무 커지면 다른 파일로 옮기거나 패키지를 만드는 것을 선호합니다.
좀 더 복잡한 것이 필요한 경우 Vite 문서에서 탐색할 수 있는 유용한 후크가 많이 있습니다. 하지만 예를 들어 아래에서 내 플러그인을 분석해 보겠습니다.
그래서 아이콘 파일을 기반으로 SVG 스프라이트를 생성하기 위한 플러그인 vite-plugin-svg-spritemap 이 있습니다.
목표는 src/icons
폴더에 있는 모든 아이콘 .svg
가져와 해당 콘텐츠를 SVG 스프라이트라고 하는 단일 .svg
파일로 수집하는 것입니다. 번들 단계부터 시작해 보겠습니다.
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
하면 다음 후크에서 사용하도록 해결되면 구성을 얻을 수 있습니다.
writeBundle
후크는 번들링 프로세스가 완료된 후 호출되며 여기서는 sprite.svg
파일을 생성합니다.
getSpriteContent
함수는 src/icons/*.svg
패턴을 기반으로 준비된 SVG 스프라이트 문자열을 반환합니다. 나는 이것에 대해 더 깊이 다루지 않을 것입니다. SVG 스프라이트 생성의 전체 과정을 설명하는 다른 기사를 확인해 보세요.
그런 다음 path.resolve()
사용하여 SVG 스프라이트 콘텐츠를 넣을 sprite.svg
에 대한 절대 경로를 생성하고, fs.ensureFileSync
.를 사용하여 파일이 존재하는지 확인하고(또는 생성) SVG 스프라이트 콘텐츠를 여기에 씁니다. .
이제 가장 흥미로운 부분은 개발 서버 단계입니다. 여기서는 writeBundle
사용할 수 없고, 개발 서버가 실행 중일 때는 파일을 호스팅할 수 없으므로 sprite.svg
에 대한 요청을 포착하려면 서버 미들웨어를 사용해야 합니다.
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
는 개발 서버를 구성하기 위한 후크입니다. Vite의 내부 미들웨어가 설치되기 전에 트리거됩니다. 제 경우에는 내부 미들웨어 다음에 커스텀 미들웨어를 추가해야 해서 함수를 반환합니다.
개발 서버에 대한 모든 요청을 포착하기 위해 사용자 정의 미들웨어를 추가하려면 server.middlewares.use()
사용합니다. 파일 동작을 에뮬레이트할 수 있도록 URL [localhost:3000/sprite.svg](http://localhost:3000/sprite.svg)
사용하여 요청을 감지하려면 이 정보가 필요합니다.
요청 URL이 /sprite.svg
가 아닌 경우 - 다음 미들웨어로 건너뜁니다(즉, 체인의 다음 핸들러로 제어권을 전달합니다).
파일 콘텐츠를 준비하기 위해 getSpriteContent
의 결과를 변수 sprite
에 넣고 구성된 헤더(콘텐츠 유형 및 200 HTTP 상태)와 함께 응답으로 보냅니다.
결과적으로 파일 동작을 시뮬레이션했습니다.
그러나 src/icons
의 파일이 변경, 삭제 또는 추가되면 서버를 다시 시작하여 getSpriteContent
통해 새 스프라이트 콘텐츠를 생성해야 합니다. 이를 위해 파일 감시 라이브러리인 Chokidar를 사용하겠습니다. 코드에 Chokidar 핸들러를 추가해 보겠습니다.
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); }); }; }, }; }
보시다시피 플러그인 생성 API는 실제로 복잡하지 않습니다. Vite나 Rollup에서 귀하의 작업에 적합한 후크를 찾으면 됩니다. 내 예에서는 Rollup.js의 writeBundle
사용하고(말했듯이 번들을 생성하는 데 사용됨) Rollup.js에는 기본 개발 서버 지원이 없기 때문에 Vite의 configureServer
사용합니다.
writeBundle
의 경우 매우 간단했습니다. SVG 스프라이트 콘텐츠를 가져와서 파일에 넣었습니다. 개발 서버의 경우 왜 그렇게 할 수 없는지 혼란스러웠습니다. 다른 작성자의 플러그인을 살펴보았는데 모두 거의 동일했습니다.
그래서 저는 configureServer
사용하고 server
인수를 통해 sprite.svg
요청을 가로채서 개발 서버에 대한 모든 요청을 트리거하는 미들웨어를 추가합니다.
앞서 언급했듯이 더 유용한 플러그인을 만들려면 후크를 탐색해야 합니다. 문서에 자세히 설명되어 있습니다.
https://vitejs.dev/guide/api-plugin#universal-hooks
https://vitejs.dev/guide/api-plugin#vite-특이적-hooks
이름 지정 측면에서 Vite에는 플러그인에 대한 몇 가지 규칙이 있으므로 완료하기 전에 확인하는 것이 좋습니다. 다음은 몇 가지 핵심 사항입니다.
vite-plugin-
접두어가 붙은 고유한 이름을 가져야 합니다.
vite-plugin
키워드를 포함합니다.
vite-plugin-vue-
, vite-plugin-react-
, vite-plugin-svelte-
)의 일부로 포함하세요.NPM에 플러그인을 게시하기로 결정했다면 지식과 전문 지식을 공유하는 것이 IT 커뮤니티의 기본 원칙이며 공동 성장을 촉진하기 때문에 권장합니다. 패키지를 게시하고 유지 관리하는 방법을 알아보려면 내 가이드 → NPM 패키지를 만드는 가장 쉬운 방법을 확인하세요.
또한 귀하의 플러그인을 vite의 커뮤니티 목록인 awesome-vite 에 제출하는 것이 좋습니다. 많은 사람들이 그곳에서 가장 적합한 플러그인을 찾고 있으며, Vite 생태계에 기여할 수 있는 좋은 기회가 될 것입니다! 플러그인을 제출하는 과정은 간단합니다. 조건을 충족하는지 확인하고 끌어오기 요청을 작성하기만 하면 됩니다. 여기에서 용어 목록을 찾을 수 있습니다.
전반적으로 Vite(롤업 아님), 오픈 소스에 특화되어야 하며 좋은 문서가 있어야 합니다. 플러그인에 행운이 있기를 바랍니다!