1.6 — Variáveis de Ambiente e Modos
Configure diferentes ambientes (dev, staging, produção) com variáveis seguras.
Objetivos da Aula
- Entender o sistema de variáveis de ambiente do Vite
- Criar arquivos
.envpara diferentes ambientes - Diferenciar variáveis públicas e privadas
- Usar modos customizados
Como Variáveis de Ambiente Funcionam
O Vite usa arquivos .env para definir variáveis de ambiente:
ARQUIVOS .env
.env Carregado em TODOS os casos .env.local Carregado em todos, ignorado pelo git .env.[mode] Carregado apenas no modo especificado .env.[mode].local Carregado no modo, ignorado pelo git
Ordem de prioridade (maior para menor):
- 1 .env.[mode].local
- 2 .env.[mode]
- 3 .env.local
- 4 .env
Modos Padrão
| Comando | Modo |
|---|---|
vite / vite dev | development |
vite build | production |
vite preview | production |
Criando Arquivos .env
.env — Base (todos os ambientes)
# .env
# Variáveis compartilhadas entre todos os ambientes
# PÚBLICAS (acessíveis no cliente)
VITE_APP_NAME=Dashboard Vite
VITE_APP_VERSION=1.0.0
# PRIVADAS (só no servidor/build)
DATABASE_URL=postgresql://localhost:5432/mydb
SECRET_KEY=minha-chave-secreta .env.development — Desenvolvimento
# .env.development
# Sobrescreve .env quando mode=development
VITE_API_URL=http://localhost:8080/api
VITE_DEBUG=true
# Banco de dev
DATABASE_URL=postgresql://localhost:5432/mydb_dev .env.production — Produção
# .env.production
# Sobrescreve .env quando mode=production
VITE_API_URL=https://api.meuprojeto.com
VITE_DEBUG=false
# Banco de produção (nunca commite senhas reais!)
DATABASE_URL=postgresql://prod-server:5432/mydb_prod .env.local — Local (não commitado)
# .env.local
# NUNCA vai para o git - para secrets locais
# Chaves pessoais de API
VITE_MAPS_API_KEY=sua-chave-pessoal-aqui
GITHUB_TOKEN=ghp_xxxxxxxxxxxx .gitignore
# .gitignore
.env.local
.env.*.local Acessando Variáveis
No Cliente (VITE_ prefix)
Importante: Apenas variáveis com prefixo VITE_ são expostas ao cliente!
// ✅ Funciona - tem prefixo VITE_
console.log(import.meta.env.VITE_APP_NAME)
console.log(import.meta.env.VITE_API_URL)
// ❌ undefined - sem prefixo VITE_
console.log(import.meta.env.DATABASE_URL) // undefined
console.log(import.meta.env.SECRET_KEY) // undefined Variáveis Automáticas
// Variáveis sempre disponíveis
import.meta.env.MODE // 'development' ou 'production'
import.meta.env.BASE_URL // URL base (config.base)
import.meta.env.PROD // true se production
import.meta.env.DEV // true se development
import.meta.env.SSR // true se server-side rendering Exemplo Prático
// src/config.js
export const config = {
appName: import.meta.env.VITE_APP_NAME,
apiUrl: import.meta.env.VITE_API_URL,
debug: import.meta.env.VITE_DEBUG === 'true',
isDev: import.meta.env.DEV,
isProd: import.meta.env.PROD,
mode: import.meta.env.MODE
}
// Uso condicional
if (config.isDev) {
console.log('Modo desenvolvimento')
console.log('Config:', config)
}
// API URL dinâmica
async function fetchData(endpoint) {
const url = `${config.apiUrl}/${endpoint}`
return fetch(url).then(r => r.json())
} TypeScript e Variáveis de Ambiente
Tipagem das Variáveis
Crie um arquivo de tipos:
// src/vite-env.d.ts
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_APP_NAME: string
readonly VITE_APP_VERSION: string
readonly VITE_API_URL: string
readonly VITE_DEBUG: string
readonly VITE_MAPS_API_KEY?: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
} Agora você tem autocomplete!
// TypeScript sabe que essas variáveis existem
const apiUrl = import.meta.env.VITE_API_URL // string
const debug = import.meta.env.VITE_DEBUG // string Modos Customizados
Criando um Modo Staging
# .env.staging
VITE_APP_NAME=Dashboard Vite (Staging)
VITE_API_URL=https://staging-api.meuprojeto.com
VITE_DEBUG=true // package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:staging": "vite build --mode staging",
"preview": "vite preview"
}
} Modo de Preview/QA
# .env.preview
VITE_APP_NAME=Dashboard Vite (Preview)
VITE_API_URL=https://preview-api.meuprojeto.com
VITE_FEATURE_FLAGS={"newUI":true,"betaFeatures":true} {
"scripts": {
"build:preview": "vite build --mode preview"
}
} Usando no vite.config.js
Carregando Variáveis na Config
// vite.config.js
import { defineConfig, loadEnv } from 'vite'
export default defineConfig(({ mode }) => {
// Carrega variáveis de ambiente
// process.cwd() = diretório atual
// '' = prefixo vazio (carrega TODAS as variáveis)
const env = loadEnv(mode, process.cwd(), '')
console.log(`Modo: ${mode}`)
console.log(`API URL: ${env.VITE_API_URL}`)
return {
define: {
// Injeta variáveis customizadas (cuidado com segurança!)
__APP_VERSION__: JSON.stringify(env.VITE_APP_VERSION)
},
server: {
proxy: {
'/api': {
target: env.VITE_API_URL,
changeOrigin: true
}
}
}
}
}) Variáveis em Tempo de Build
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
define: {
// Disponíveis em todo o código
__BUILD_TIME__: JSON.stringify(new Date().toISOString()),
__COMMIT_HASH__: JSON.stringify(process.env.COMMIT_SHA || 'local')
}
}) // No código
console.log(`Build: ${__BUILD_TIME__}`)
console.log(`Commit: ${__COMMIT_HASH__}`) Substituição de Variáveis em HTML
index.html
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8" />
<title>%VITE_APP_NAME%</title>
<meta name="version" content="%VITE_APP_VERSION%">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html> O Vite substitui %VITE_*% automaticamente!
Segurança
⚠️ Regras Importantes
SEGURANCA DE VARIAVEIS
VITE_ (publico) — Visivel no navegador, ok expor
- URLs de API publicas
- Nomes de app
- Feature flags publicos
- Chaves de API publicas (Google Maps, etc)
SEM PREFIXO (privado) — NUNCA exposto, seguro
- Senhas de banco
- Tokens de autenticacao
- Chaves secretas
- API keys privadas
NUNCA faca:
VITE_DATABASE_PASSWORD=...VITE_STRIPE_SECRET_KEY=...- Commitar .env.local
Validação de Variáveis
// src/env.js
// Valida que todas as variáveis necessárias existem
const requiredEnvVars = [
'VITE_APP_NAME',
'VITE_API_URL'
]
for (const envVar of requiredEnvVars) {
if (!import.meta.env[envVar]) {
throw new Error(`Variável de ambiente ${envVar} não definida!`)
}
}
export const env = {
appName: import.meta.env.VITE_APP_NAME,
apiUrl: import.meta.env.VITE_API_URL,
debug: import.meta.env.VITE_DEBUG === 'true',
isDev: import.meta.env.DEV,
isProd: import.meta.env.PROD
} 🎯 Mini-Projeto: Configuração Multi-Ambiente
Vamos configurar nosso Dashboard para múltiplos ambientes:
Passo 1: Criar arquivos .env
# .env
VITE_APP_NAME=Dashboard Vite
VITE_APP_VERSION=1.0.0 # .env.development
VITE_API_URL=http://localhost:3001
VITE_DEBUG=true
VITE_ENVIRONMENT=development # .env.staging
VITE_API_URL=https://staging-api.example.com
VITE_DEBUG=true
VITE_ENVIRONMENT=staging # .env.production
VITE_API_URL=https://api.example.com
VITE_DEBUG=false
VITE_ENVIRONMENT=production Passo 2: Criar módulo de configuração
// src/config/env.js
// Validação
const required = ['VITE_APP_NAME', 'VITE_API_URL']
for (const key of required) {
if (!import.meta.env[key]) {
console.error(`❌ Variável ${key} não definida!`)
}
}
// Exporta configuração tipada
export const env = {
app: {
name: import.meta.env.VITE_APP_NAME,
version: import.meta.env.VITE_APP_VERSION || '0.0.0'
},
api: {
url: import.meta.env.VITE_API_URL
},
flags: {
debug: import.meta.env.VITE_DEBUG === 'true'
},
runtime: {
mode: import.meta.env.MODE,
isDev: import.meta.env.DEV,
isProd: import.meta.env.PROD,
environment: import.meta.env.VITE_ENVIRONMENT || 'unknown'
}
}
// Log em desenvolvimento
if (env.flags.debug) {
console.log('🔧 Configuração carregada:', env)
} Passo 3: Componente de status do ambiente
// src/components/EnvironmentBadge.js
import { env } from '@/config/env.js'
const colors = {
development: '#22c55e', // verde
staging: '#f59e0b', // amarelo
production: '#ef4444' // vermelho
}
export function createEnvironmentBadge() {
const badge = document.createElement('div')
badge.className = 'environment-badge'
badge.style.cssText = `
position: fixed;
bottom: 1rem;
right: 1rem;
padding: 0.5rem 1rem;
border-radius: 9999px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
background: ${colors[env.runtime.environment] || '#666'};
color: white;
z-index: 9999;
`
badge.textContent = `${env.runtime.environment} • v${env.app.version}`
// Não mostra em produção (opcional)
if (env.runtime.isProd && !env.flags.debug) {
badge.style.display = 'none'
}
return badge
} Passo 4: Atualizar main.js
// src/main.js
import '@/style.css'
import { env } from '@/config/env.js'
import { createEnvironmentBadge } from '@components/EnvironmentBadge.js'
// ... outros imports
function renderApp() {
// ... código existente
// Adiciona badge de ambiente
document.body.appendChild(createEnvironmentBadge())
// Atualiza título com nome do app
document.title = `${env.app.name} - ${env.runtime.environment}`
}
renderApp() Passo 5: Scripts no package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:staging": "vite build --mode staging",
"preview": "vite preview",
"preview:staging": "vite preview --mode staging"
}
} ✅ Desafio da Aula
Objetivo
Criar um sistema de feature flags baseado em variáveis de ambiente.
Instruções
- Crie uma variável
VITE_FEATURE_FLAGScom JSON de features - Crie um módulo que parseia e expõe as flags
- Use as flags para mostrar/esconder um card “Beta Features”
Exemplo de .env
VITE_FEATURE_FLAGS={"darkMode":true,"betaCard":true,"analytics":false} Spec de Verificação
- O módulo
featureFlagsexporta um objeto com as flags - Quando
betaCard: true, um card especial aparece no dashboard - Quando
betaCard: false, o card não aparece
Solução
🔍 Clique para ver a solução
// src/config/features.js
const flagsJson = import.meta.env.VITE_FEATURE_FLAGS || '{}'
let flags = {}
try {
flags = JSON.parse(flagsJson)
} catch (e) {
console.error('Erro ao parsear feature flags:', e)
}
export const featureFlags = {
darkMode: flags.darkMode ?? false,
betaCard: flags.betaCard ?? false,
analytics: flags.analytics ?? false
}
export function isEnabled(flag) {
return featureFlags[flag] === true
} // src/components/BetaCard.js
import { isEnabled } from '@/config/features.js'
export function createBetaCard() {
if (!isEnabled('betaCard')) {
return null
}
const card = document.createElement('div')
card.className = 'performance-card beta-card'
card.innerHTML = `
<span class="beta-badge">BETA</span>
<h3 class="card-title">Funcionalidade Beta</h3>
<p>Esta é uma funcionalidade experimental!</p>
`
return card
} // src/main.js
import { createBetaCard } from '@components/BetaCard.js'
// Na função de render
const betaCard = createBetaCard()
if (betaCard) {
document.querySelector('.cards-grid').appendChild(betaCard)
}Próxima aula: 1.7 — Build de Produção e Otimização