kb.erickguedes.com
Vite: Build Tool do Futuro

Plugins e Processamento CSS

Aula 2 de 4

Plugin API

Vite possui um sistema de plugins baseado na API de plugins do Rollup, com hooks específicos do Vite.

Estrutura de um Plugin

// plugins/my-plugin.ts
import type { Plugin, ResolvedConfig } from 'vite';

export function myPlugin(options?: { prefix?: string }): Plugin {
  let config: ResolvedConfig;

  return {
    name: 'my-plugin',

    // Hook de configuração
    config(userConfig, { command, mode }) {
      return {
        // Modificar config aqui
        define: {
          __PLUGIN_VERSION__: JSON.stringify('1.0.0')
        }
      };
    },

    // Hook de resolução de ID
    resolveId(id) {
      if (id === 'virtual:module') {
        return '\0virtual:module';
      }
    },

    // Hook de load (módulos virtuais)
    load(id) {
      if (id === '\0virtual:module') {
        return `export const version = '1.0.0'`;
      }
    },

    // Hook de transformação de código
    transform(code, id) {
      if (id.endsWith('.special.ts')) {
        return {
          code: code.replace(/console\.log/g, 'console.warn'),
          map: null
        };
      }
    },

    // Hooks específicos Vite
    configureServer(server) {
      server.middlewares.use((req, res, next) => {
        console.log(`Request: ${req.url}`);
        next();
      });
    },

    handleHotUpdate({ file, server }) {
      console.log(`Hot update: ${file}`);
    },

    closeBundle() {
      console.log('Build finalizado');
    }
  };
}

Módulos Virtuais

// plugins/virtual-config.ts
import type { Plugin } from 'vite';

export function virtualConfig(): Plugin {
  const virtualModuleId = 'virtual:config';
  const resolvedVirtualModuleId = '\0' + virtualModuleId;

  return {
    name: 'virtual-config',
    resolveId(id) {
      if (id === virtualModuleId) return resolvedVirtualModuleId;
    },
    load(id) {
      if (id === resolvedVirtualModuleId) {
        return `
          export const appConfig = {
            version: '1.0.0',
            environment: '${process.env.NODE_ENV}',
            features: ['auth', 'dashboard', 'analytics']
          };
        `;
      }
    }
  };
}
// Uso no código
import { appConfig } from 'virtual:config';
console.log(appConfig.version); // 1.0.0

Plugins Essenciais

React

npm install @vitejs/plugin-react
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      jsxRuntime: 'automatic',
      babel: {
        plugins: ['@emotion/babel-plugin']
      },
      fastRefresh: true
    })
  ]
});

Vue

npm install @vitejs/plugin-vue
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()]
});

ESLint

npm install -D vite-plugin-eslint
import eslint from 'vite-plugin-eslint';

export default defineConfig({
  plugins: [
    eslint({
      cache: false,
      fix: true
    })
  ]
});

SVGR

npm install -D @svgr/rollup
import svgr from '@svgr/rollup';

export default defineConfig({
  plugins: [svgr()]
});
import Logo from './logo.svg?react';

function App() {
  return <Logo width={100} height={100} />;
}

tsconfig-paths

npm install -D vite-tsconfig-paths
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig({
  plugins: [tsconfigPaths()] // Lê paths do tsconfig.json
});

CSS

PostCSS

npm install -D postcss autoprefixer
// postcss.config.js
export default {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: ['> 1%', 'last 2 versions']
    },
    'postcss-nesting': {},
    'postcss-preset-env': {
      stage: 2,
      features: {
        'nesting-rules': true
      }
    }
  }
};

CSS Modules

/* src/components/Button.module.css */
.button {
  padding: 8px 16px;
  border-radius: 4px;
}

.primary {
  background: #646cff;
  color: white;
}
// src/components/Button.tsx
import styles from './Button.module.css';

export function Button({ primary }: { primary?: boolean }) {
  return (
    <button
      className={`${styles.button} ${primary ? styles.primary : ''}`}
    >
      Click me
    </button>
  );
}

Tailwind CSS

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
// tailwind.config.js
export default {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        primary: '#646cff'
      }
    }
  },
  plugins: []
};
/* src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

Lightning CSS

// vite.config.ts
export default defineConfig({
  css: {
    transformer: 'lightningcss',
    lightningcss: {
      drafts: {
        nesting: true,
        customMedia: true
      }
    }
  }
});

@import Inlining

Vite inlineia automaticamente arquivos CSS importados.

/* src/styles/base.css */
@import './reset.css';
@import './variables.css';
@import './typography.css';

body {
  font-family: system-ui;
}
// vite.config.ts
export default defineConfig({
  css: {
    // Desabilitar inlining (se necessário)
    preprocessorOptions: {
      css: {
        additionalData: ''
      }
    }
  }
});

Lab: Exercício - Configuração com Plugins e CSS

// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import svgr from '@svgr/rollup';
import eslint from 'vite-plugin-eslint';

export default defineConfig({
  plugins: [
    react(),
    tsconfigPaths(),
    svgr(),
    eslint({ fix: true })
  ],
  css: {
    modules: {
      localsConvention: 'camelCaseOnly'
    },
    preprocessorOptions: {
      scss: {
        additionalData: `
          @import "@/styles/variables";
          @import "@/styles/mixins";
        `
      }
    }
  }
});
npm install -D sass
npm run dev

Sistema de plugins do Vite é flexível (baseado no Rollup). Plugins podem criar módulos virtuais, transformar código e modificar configuração. CSS Modules, PostCSS, Tailwind e Lightning CSS são suportados nativamente. SCSS/Less precisam de preprocessor instalado.