No desenvolvimento front-end moderno, a combinação de Vue 3 com Vite oferece um ambiente de desnevolvimento ágil e performático. Projetos frequentemente evoluem para abranger múltiplos subsistemas que requerem compilações separadas (dist). Este guia detalha como configurar um ambiente Vue 3 com Vite para suportar múltiplos projetos, garantindo a geração de múltiplos pacotes de distribuição.
Configurando a Estrutura do Projeto Principal
Inicie um novo projeto Vue 3 utilizando o Vite:
npm create vue@latest my-monorepo
Estrutura de Diretórios dos Subsistemas
Organize seus subsistemas dentro do diretório src do projeto principal. Por exemplo:
my-monorepo/
├── public/
├── src/
│ ├── assets/
│ ├── components/
│ ├── projects/
│ │ ├── projectA/
│ │ │ ├── App.vue
│ │ │ └── main.js
│ │ ├── projectB/
│ │ │ ├── App.vue
│ │ │ └── main.js
│ │ └── router/
│ │ └── index.js
│ ├── App.vue
│ ├── main.js
│ └── index.html
├── index.html
├── vite.config.js
├── package.json
├── projectConfig.js
└── dynamic-build-all.js
Arquivos Específicos dos Subsistemas
Cada subsistema necessitará de seus próprios App.vue e main.js. Adapte os caminhos de recursos e importações conforme necessário. Por exemplo, em src/projects/projectA/App.vue:
<script setup>
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from '../../components/HelloWorld.vue' // Ajuste o caminho
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="../../assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="Bem-vindo ao Projeto A!" />
<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">Sobre</RouterLink>
</nav>
</div>
</header>
<RouterView />
</template>
<style scoped>
/* Estilos aqui */
</style>
E em src/projects/projectA/main.js:
import '../../assets/main.css' // Ajuste o caminho
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from '../../router' // Ajuste o caminho
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
Para cada subsistema, crie um arquivo HTML correspondente (ou reutilize o index.html principal se os títulos e ícones forem idênticos). Por exemplo, projectA.html:
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Projeto A</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/projects/projectA/main.js"></script>
</body>
</html>
Configurando Múltiplas Saídas (Dist)
Crie um arquivo projectConfig.js para centralizar as configurações de entrada de cada subsistema:
export const projectConfigs = {
projectA: {
minify: true,
pages: [
{
filename: 'projecta', // Nome do arquivo HTML de saída
entry: 'src/projects/projectA/main.js', // Ponto de entrada do script
template: 'projectA.html', // Arquivo HTML de modelo
},
],
},
projectB: {
minify: true,
pages: [
{
filename: 'projectb',
entry: 'src/projects/projectB/main.js',
template: 'projectB.html',
},
],
}
}
Modifique seu arquivo vite.config.js para incorporar essas configurações:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { createHtmlPlugin } from 'vite-plugin-html'
import { resolve } from 'node:path'
import { projectConfigs } from './projectConfig.js'
// Obtém o nome do projeto através de variáveis de ambiente
const projectName = process.env.PROJECT_NAME
// Verifica se o nome do projeto foi fornecido
if (!projectName || !projectConfigs[projectName]) {
console.error('Erro: PROJECT_NAME não definido ou inválido. Use um dos seguintes: ' + Object.keys(projectConfigs).join(', '));
process.exit(1);
}
const currentProjectConfig = projectConfigs[projectName];
export default defineConfig({
base: './',
publicDir: 'public',
plugins: [
vue(),
createHtmlPlugin({
// Configura o plugin para usar as páginas do projeto atual
entry: currentProjectConfig.pages[0].entry, // Define o ponto de entrada principal para o plugin HTML
template: currentProjectConfig.pages[0].template, // Define o template principal
// Você pode precisar ajustar a lógica do createHtmlPlugin para lidar com múltiplos 'pages' explicitamente
// se ele não suportar nativamente em sua configuração atual.
// Uma abordagem comum é gerar cada página separadamente.
// Para simplicidade, este exemplo assume que o 'entry' e 'template' são para a configuração principal.
})
],
resolve: {
alias: {
'@': resolve(__dirname, 'src')
}
},
build: {
cssCodeSplit: true,
emptyOutDir: true,
sourcemap: false,
assetsDir: 'assets',
// O diretório de saída agora é dinâmico
outDir: `dist-${projectName}`,
rollupOptions: {
input: {
// Mapeia os pontos de entrada para cada projeto
// Isso é crucial para o Vite entender quais arquivos compilar
...currentProjectConfig.pages.reduce((acc, page) => {
acc[page.filename] = page.entry;
return acc;
}, {}),
},
output: {
compact: true,
entryFileNames: "assets/js/[name]-[hash].js",
chunkFileNames: "assets/js/[name]-[hash].js",
assetFileNames: "assets/[ext]/[name].[ext]",
// Garante que cada entrada tenha sua própria saída HTML se using build.rollupOptions.input for multiple entries
// Para múltiplas páginas, pode ser necessário um plugin adicional ou configuração mais complexa
// A configuração 'pages' do createHtmlPlugin é mais adequada para este cenário.
}
}
},
})
Atualize o script build no seu package.json:
"scripts": {
"dev": "vite",
"build": "node ./scripts/build-all.js",
"preview": "vite preview"
},
Crie um script para gerenciar as compilações de múltiplos projetos, por exemplo, scripts/build-all.js:
import { execSync } from 'child_process';
import { projectConfigs } from '../projectConfig.js';
const projectNames = Object.keys(projectConfigs);
projectNames.forEach(projectName => {
console.log(`\nIniciando a compilação para o projeto: ${projectName}...`);
try {
// Define a variável de ambiente PROJECT_NAME e executa o comando de build do Vite
execSync(`cross-env PROJECT_NAME=${projectName} vite build`, { stdio: 'inherit' });
console.log(`Compilação do projeto ${projectName} concluída com sucesso.`);
} catch (error) {
console.error(`Erro durante a compilação do projeto ${projectName}:`, error);
process.exit(1); // Sai com erro se um projeto falhar
}
});
console.log('\nTodos os projetos foram compilados.');
O arquivo projectConfig.js agora é a fonte única de verdade para os projetos a serem compilados. Não é mais necessário um arquivo separado como projects.js.
Executando a Compilação
Execute o script de compilação para gerar os pacotes individuais:
npm run build
Após a execução, você encontrará diretórios dist-projectA, dist-projectB, etc., contendo os pacotes compilados para cada subsistema.