paint-brush
Creación de un complemento personalizado para Vite: la guía más sencillapor@gmakarov
3,574 lecturas
3,574 lecturas

Creación de un complemento personalizado para Vite: la guía más sencilla

por German Makarov9m2024/01/21
Read on Terminal Reader

Demasiado Largo; Para Leer

Para el servidor de desarrollo, utiliza esbuild con módulos ES nativos, que son compatibles con los navegadores modernos, y no necesitamos agrupar el código en un solo archivo, y nos brinda HRM (Reemplazo de módulo en caliente) rápido. Para el paquete, utiliza rollup.js porque es flexible y tiene un ecosistema grande; permite la creación de paquetes de producción altamente optimizados con diferentes formatos de salida. La interfaz del complemento de Vite se basa en la de Rollup pero con opciones y enlaces adicionales para trabajar con el servidor de desarrollo.
featured image - Creación de un complemento personalizado para Vite: la guía más sencilla
German Makarov HackerNoon profile picture
0-item

Vite se está volviendo cada vez más popular entre los desarrolladores, pero como la comunidad no es tan grande (como en Webpack ), es posible que necesites crear tu propio complemento personalizado para resolver tus problemas. En este artículo, discutiremos cómo crear un complemento para Vite y desglosaré mi propio complemento.

Cómo funcionan los complementos en Vite

Para crear un complemento, es importante saber que Vite utiliza diferentes sistemas de compilación para el servidor de desarrollo (comando vite ) y el paquete (comando vite build ).


Para el servidor de desarrollo, utiliza esbuild con módulos ES nativos, que son compatibles con los navegadores modernos, y no necesitamos agrupar el código en un solo archivo, y nos brinda HRM (Reemplazo de módulo en caliente) rápido.


Para el paquete, utiliza rollup.js porque es flexible y tiene un ecosistema grande; permite la creación de paquetes de producción altamente optimizados con diferentes formatos de salida.


La interfaz del complemento de Vite se basa en la de Rollup pero con opciones y enlaces adicionales para trabajar con el servidor de desarrollo.

Crear un complemento básico

Cuando crea un complemento, puede integrarlo en su vite.config.js . No es necesario crear un nuevo paquete para ello. Una vez que vea que un complemento ha sido útil en sus proyectos, considere compartirlo con la comunidad y contribuir al ecosistema de Vite.


Además, dado que rollup.js tiene una comunidad y un ecosistema más grandes, podría considerar crear un complemento para rollup.js, y funcionará igual de bien en Vite. Por lo tanto, si la funcionalidad de su complemento funciona solo para el paquete, puede utilizar el complemento rollup.js en lugar de Vite, y los usuarios pueden usar su complemento acumulativo en sus proyectos de Vite sin ningún problema.


Si crea un complemento para el resumen, cubrirá a más usuarios que usan solo rollup.js. Si su complemento afectará al servidor de desarrollo, entonces elija el complemento Vite.


Comencemos a crear un complemento directamente en 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(), ], });


En este ejemplo, he creado un complemento llamado myPlugin que imprime la configuración de Vite tan pronto como se resuelve en la consola en ambas etapas: servidor de desarrollo y paquete. Si quiero imprimir la configuración solo en el modo de servidor de desarrollo, entonces debo agregar apply: 'serve' y apply: 'build' para el paquete.


 // 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(), ], });


Además, puedo devolver una variedad de complementos; Es útil para separar la funcionalidad del servidor de desarrollo y del paquete:


 // 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(), ], });


Y eso es prácticamente todo; puedes agregar fácilmente pequeños complementos a la configuración de Vite. Y si un complemento se vuelve demasiado grande, prefiero moverlo a otro archivo o incluso crear un paquete.


Si necesita algo más complejo, hay muchos enlaces útiles que puede explorar en la documentación de Vite. Pero como ejemplo, analicemos mi propio complemento a continuación.

Desglosando un complemento real

Entonces, tengo un complemento para crear sprites SVG basados en archivos de íconos: vite-plugin-svg-spritemap .

El objetivo es capturar todos los íconos .svg en la carpeta src/icons y recopilar su contenido en un único archivo .svg que se llama sprite SVG. Comencemos desde la etapa del paquete:


 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); }, }; }


  1. Hook configResolved nos permite obtener la configuración cuando esté resuelta para usarla en los siguientes ganchos;


  2. El gancho writeBundle se llama una vez finalizado el proceso de agrupación, y aquí crearé el archivo sprite.svg ;


  3. La función getSpriteContent devuelve una cadena de sprites SVG preparados según el patrón src/icons/*.svg . No profundizaré con este; puedes consultar mi otro artículo que explica todo el proceso de generación de sprites SVG ;


  4. Luego, creo la ruta absoluta al sprite.svg para colocar el contenido del sprite SVG con path.resolve() , me aseguro de que el archivo exista (o creo uno) con fs.ensureFileSync ., y escribo el contenido del sprite SVG en él .


Ahora, venga la parte más interesante: la etapa del servidor de desarrollo. No puedo usar writeBundle aquí y no puedo alojar archivos cuando el servidor de desarrollo se está ejecutando, por lo que necesitamos usar middleware del servidor para capturar la solicitud a 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); }); }; }, }; }


  1. configureServer es un enlace para configurar el servidor de desarrollo. Se activa antes de que se instale el middleware interno de Vite; en mi caso, necesito agregar middleware personalizado después del middleware interno, por lo que devuelvo una función;


  2. Para agregar middleware personalizado para capturar cada solicitud al servidor de desarrollo, uso server.middlewares.use() . Lo necesito para detectar solicitudes con la URL [localhost:3000/sprite.svg](http://localhost:3000/sprite.svg) , para poder emular el comportamiento del archivo;


  3. Si la URL de solicitud no es /sprite.svg , pase al siguiente middleware (es decir, pase el control al siguiente controlador de la cadena);


  4. Para preparar el contenido del archivo, coloco el resultado de getSpriteContent en la variable sprite y lo envío como respuesta con encabezados configurados (tipo de contenido y estado HTTP 200).


Como resultado, simulé el comportamiento del archivo.


Pero si se cambian, eliminan o agregan archivos en src/icons , debemos reiniciar el servidor para generar nuevo contenido de sprites a través de getSpriteContent ; Para esto, usaré la biblioteca de observación de archivos: chokidar . Agreguemos controladores chokidar al código:


 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); }); }; }, }; }


Como puedes ver, la API de creación de complementos no es realmente complicada. Sólo necesita encontrar ganchos de Vite o Rollup que se adapten a sus tareas. En mi ejemplo, estoy usando writeBundle de Rollup.js (como dije, se usa para generar el paquete) y configureServer de Vite porque Rollup.js no tiene soporte de servidor de desarrollo nativo.


En el caso de writeBundle fue muy simple, tomamos el contenido del sprite SVG y lo colocamos en un archivo. En el caso del servidor de desarrollo, me confundió por qué no podía hacer lo mismo; Miré los complementos de otros autores y todos hacen más o menos lo mismo.


Entonces, uso configureServer y, a través del argumento server , agrego middleware que activa cada solicitud al servidor de desarrollo al interceptar la solicitud sprite.svg .

Usando ganchos Vite

Como mencioné antes, para crear complementos más útiles, debes explorar los enlaces. Se explican detalladamente en la documentación:

https://vitejs.dev/guide/api-plugin#universal-hooks

https://vitejs.dev/guide/api-plugin#vite-specific-hooks

Cómo nombrar un complemento

En términos de nombres, Vite tiene algunas convenciones para complementos, por lo que será mejor que lo revises antes de terminar. Aquí hay algunos puntos clave:


  • Los complementos de Vite deben tener un nombre único con un prefijo vite-plugin- ;


  • Incluya la palabra clave vite-plugin en package.json;


  • Incluya una sección en los documentos del complemento que explique por qué es un complemento exclusivo de Vite (por ejemplo, utiliza enlaces de complementos específicos de Vite);


  • Si su complemento solo funcionará para un marco específico, incluya su nombre como parte del prefijo ( vite-plugin-vue- , vite-plugin-react- , vite-plugin-svelte- ).

Cómo publicar y compartir su complemento

Si decide publicar su complemento en NPM, lo recomiendo porque compartir conocimientos y experiencia es un principio fundamental de la comunidad de TI, fomentando el crecimiento colectivo. Para aprender cómo publicar y mantener su paquete, consulte mi guía → La forma más sencilla de crear un paquete NPM .


También recomiendo enviar su complemento a la lista de la comunidad de vite: awesome-vite . Mucha gente busca allí los complementos más adecuados y sería una gran oportunidad para contribuir al ecosistema de Vite. El proceso de enviar su complemento allí es simple: solo asegúrese de cumplir con los términos y crear una solicitud de extracción. Puede encontrar la lista de términos aquí .


En general, debe ser específico de Vite (no un resumen), de código abierto y tener buena documentación. ¡Buena suerte con tus complementos!