Integração com Vite

Aplicações JavaScript modernas exigem ferramentas de construção sofisticadas. Nette Assets oferece integração de primeira classe com Vite, a ferramenta de construção frontend de próxima geração. Obtenha desenvolvimento ultrarrápido com Hot Module Replacement (HMR) e construções de produção otimizadas com zero complicações de configuração.

  • Zero configuração – ponte automática entre Vite e templates PHP
  • Gerenciamento completo de dependências – uma tag lida com todos os assets
  • Hot Module Replacement – atualizações instantâneas de JavaScript e CSS
  • Construções de produção otimizadas – code splitting e tree shaking

Nette Assets se integra perfeitamente com Vite, para que você obtenha todos esses benefícios enquanto escreve seus templates como de costume.

Configurando o Vite

Vamos configurar o Vite passo a passo. Não se preocupe se você é novo em ferramentas de construção – vamos explicar tudo!

Passo 1: Instalar o Vite

Primeiro, instale o Vite e o plugin Nette em seu projeto:

npm install -D vite @nette/vite-plugin

Isso instala o Vite e um plugin especial que ajuda o Vite a funcionar perfeitamente com o Nette.

Passo 2: Estrutura do Projeto

A abordagem padrão é colocar os arquivos de asset de origem em uma pasta assets/ na raiz do seu projeto, e as versões compiladas em www/assets/:

web-project/
├── assets/                   ← arquivos de origem (SCSS, TypeScript, imagens de origem)
│   ├── public/               ← arquivos estáticos (copiados como estão)
│   │   └── favicon.ico
│   ├── images/
│   │   └── logo.png
│   ├── app.js                ← ponto de entrada principal
│   └── style.css             ← seus estilos
└── www/                      ← diretório público (document root)
	├── assets/               ← arquivos compilados irão para cá
	└── index.php

A pasta assets/ contém seus arquivos de origem – o código que você escreve. O Vite processará esses arquivos e colocará as versões compiladas em www/assets/.

Passo 3: Configurar o Vite

Crie um arquivo vite.config.ts na raiz do seu projeto. Este arquivo informa ao Vite onde encontrar seus arquivos de origem e onde colocar os compilados.

O plugin Nette Vite vem com padrões inteligentes que simplificam a configuração. Ele assume que seus arquivos de origem frontend estão no diretório assets/ (opção root) e os arquivos compilados vão para www/assets/ (opção outDir). Você só precisa especificar o ponto de entrada:

import { defineConfig } from 'vite';
import nette from '@nette/vite-plugin';

export default defineConfig({
	plugins: [
		nette({
			entry: 'app.js',
		}),
	],
});

Se você quiser especificar outro nome de diretório para construir seus assets, precisará alterar algumas opções:

export default defineConfig({
	root: 'assets', // diretório raiz dos assets de origem

	build: {
		outDir: '../www/assets',  // onde os arquivos compilados vão
	},

	// ... outras configurações ...
});

O caminho outDir é considerado relativo a root, por isso há ../ no início.

Passo 4: Configurar o Nette

Informe ao Nette Assets sobre o Vite em seu common.neon:

assets:
	mapping:
		default:
			type: vite      # informa ao Nette para usar o ViteMapper
			path: assets

Passo 5: Adicionar scripts

Adicione estes scripts ao seu package.json:

{
	"scripts": {
		"dev": "vite",
		"build": "vite build"
	}
}

Agora você pode:

  • npm run dev – iniciar o servidor de desenvolvimento com hot reloading
  • npm run build – criar arquivos de produção otimizados

Pontos de Entrada

Um ponto de entrada é o arquivo principal onde sua aplicação começa. A partir deste arquivo, você importa outros arquivos (CSS, módulos JavaScript, imagens), criando uma árvore de dependências. O Vite segue essas importações e agrupa tudo.

Exemplo de ponto de entrada assets/app.js:

// Importa estilos
import './style.css'

// Importa módulos JavaScript
import netteForms from 'nette-forms';
import naja from 'naja';

// Inicializa sua aplicação
netteForms.initOnLoad();
naja.initialize();

No template você pode inserir um ponto de entrada da seguinte forma:

{asset 'app.js'}

Nette Assets gera automaticamente todas as tags HTML necessárias – JavaScript, CSS e quaisquer outras dependências.

Múltiplos Pontos de Entrada

Aplicações maiores geralmente precisam de pontos de entrada separados:

export default defineConfig({
	plugins: [
		nette({
			entry: [
				'app.js',      // páginas públicas
				'admin.js',    // painel de administração
			],
		}),
	],
});

Use-os em diferentes templates:

{* Em páginas públicas *}
{asset 'app.js'}

{* No painel de administração *}
{asset 'admin.js'}

Importante: Arquivos de Origem vs. Compilados

É crucial entender que em produção você só pode carregar:

  1. Pontos de entrada definidos em entry
  2. Arquivos do diretório assets/public/

Você não pode carregar usando {asset} arquivos arbitrários de assets/ – apenas assets referenciados por arquivos JavaScript ou CSS. Se seu arquivo não for referenciado em nenhum lugar, ele não será compilado. Se você quiser que o Vite esteja ciente de outros assets, você pode movê-los para a pasta pública.

Observe que, por padrão, o Vite incorporará todos os assets menores que 4KB, então você não poderá referenciar esses arquivos diretamente. (Consulte a documentação do Vite).

{* ✓ Isso funciona - é um ponto de entrada *}
{asset 'app.js'}

{* ✓ Isso funciona - está em assets/public/ *}
{asset 'favicon.ico'}

{* ✗ Isso não funcionará - arquivo aleatório em assets/ *}
{asset 'components/button.js'}

Modo de Desenvolvimento

O modo de desenvolvimento é completamente opcional, mas oferece benefícios significativos quando ativado. A principal vantagem é o Hot Module Replacement (HMR) – veja as mudanças instantaneamente sem perder o estado da aplicação, tornando a experiência de desenvolvimento muito mais suave e rápida.

Vite é uma ferramenta de construção moderna que torna o desenvolvimento incrivelmente rápido. Ao contrário dos bundlers tradicionais, o Vite serve seu código diretamente para o navegador durante o desenvolvimento, o que significa um início instantâneo do servidor, não importa o tamanho do seu projeto, e atualizações ultrarrápidas.

Iniciando o Servidor de Desenvolvimento

Execute o servidor de desenvolvimento:

npm run dev

Você verá:

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

Mantenha este terminal aberto durante o desenvolvimento.

O plugin Nette Vite detecta automaticamente quando:

  1. O servidor de desenvolvimento Vite está em execução
  2. Sua aplicação Nette está em modo de depuração

Quando ambas as condições são atendidas, o Nette Assets carrega os arquivos do servidor de desenvolvimento Vite em vez do diretório compilado:

{asset 'app.js'}
{* Em desenvolvimento: <script src="http://localhost:5173/app.js" type="module"></script> *}
{* Em produção: <script src="/assets/app-4a8f9c7.js" type="module"></script> *}

Nenhuma configuração necessária – simplesmente funciona!

Trabalhando em Diferentes Domínios

Se o seu servidor de desenvolvimento estiver sendo executado em algo diferente de localhost (como myapp.local), você pode encontrar problemas de CORS (Cross-Origin Resource Sharing). CORS é um recurso de segurança em navegadores da web que bloqueia solicitações entre diferentes domínios por padrão. Quando sua aplicação PHP é executada em myapp.local, mas o Vite é executado em localhost:5173, o navegador os vê como domínios diferentes e bloqueia as solicitações.

Você tem duas opções para resolver isso:

Opção 1: Configurar CORS

A solução mais simples é permitir solicitações cross-origin de sua aplicação PHP:

export default defineConfig({
	// ... outras configurações ...

	server: {
		cors: {
			origin: 'http://myapp.local',  // URL da sua aplicação PHP
		},
	},
});

Opção 2: Executar o Vite em seu domínio

A outra solução é fazer com que o Vite seja executado no mesmo domínio da sua aplicação PHP.

export default defineConfig({
	// ... outras configurações ...

	server: {
		host: 'myapp.local',  // o mesmo da sua aplicação PHP
	},
});

Na verdade, mesmo neste caso, você precisa configurar o CORS porque o servidor de desenvolvimento é executado no mesmo hostname, mas em uma porta diferente. No entanto, neste caso, o CORS é configurado automaticamente pelo plugin Nette Vite.

Desenvolvimento HTTPS

Se você desenvolve em HTTPS, precisa de certificados para o seu servidor de desenvolvimento Vite. A maneira mais fácil é usar um plugin que gera certificados automaticamente:

npm install -D vite-plugin-mkcert

Veja como configurá-lo em vite.config.ts:

import mkcert from 'vite-plugin-mkcert';

export default defineConfig({
	// ... outras configurações ...

	plugins: [
		mkcert(),  // gera certificados automaticamente e habilita https
		nette(),
	],
});

Observe que, se você estiver usando a configuração CORS (Opção 1 acima), precisará atualizar a URL de origem para usar https:// em vez de http://.

Construções de Produção

Crie arquivos de produção otimizados:

npm run build

O Vite irá:

  • Minificar todo o JavaScript e CSS
  • Dividir o código em chunks ideais
  • Gerar nomes de arquivo com hash para cache-busting
  • Criar um arquivo de manifesto para Nette Assets

Exemplo de saída:

www/assets/
├── app-4f3a2b1c.js       # Seu JavaScript principal (minificado)
├── app-7d8e9f2a.css      # CSS extraído (minificado)
├── vendor-8c4b5e6d.js    # Dependências compartilhadas
└── .vite/
	└── manifest.json     # Mapeamento para Nette Assets

Os nomes de arquivo com hash garantem que os navegadores sempre carreguem a versão mais recente.

Pasta Pública

Os arquivos no diretório assets/public/ são copiados para a saída sem processamento:

assets/
├── public/
│   ├── favicon.ico
│   ├── robots.txt
│   └── images/
│       └── og-image.jpg
├── app.js
└── style.css

Referencie-os normalmente:

{* Estes arquivos são copiados como estão *}
<link rel="icon" href={asset 'favicon.ico'}>
<meta property="og:image" content={asset 'images/og-image.jpg'}>

Para arquivos públicos, você pode usar os recursos do FilesystemMapper:

assets:
	mapping:
		default:
			type: vite
			path: assets
			extension: [webp, jpg, png]  # Tenta WebP primeiro
			versioning: true             # Adiciona cache-busting

Na configuração vite.config.ts você pode alterar a pasta pública usando a opção publicDir.

Importações Dinâmicas

O Vite divide automaticamente o código para carregamento ideal. As importações dinâmicas permitem que você carregue o código apenas quando ele é realmente necessário, reduzindo o tamanho inicial do bundle:

// Carrega componentes pesados sob demanda
button.addEventListener('click', async () => {
	let { Chart } = await import('./components/chart.js')
	new Chart(data)
})

As importações dinâmicas criam chunks separados que são carregados apenas quando necessário. Isso é chamado de “code splitting” e é um dos recursos mais poderosos do Vite. Quando você usa importações dinâmicas, o Vite cria automaticamente arquivos JavaScript separados para cada módulo importado dinamicamente.

A tag {asset 'app.js'} não pré-carrega automaticamente esses chunks dinâmicos. Este é um comportamento intencional – não queremos baixar código que talvez nunca seja usado. Os chunks são baixados apenas quando a importação dinâmica é executada.

No entanto, se você souber que certas importações dinâmicas são críticas e serão necessárias em breve, você pode pré-carregá-las:

{* Ponto de entrada principal *}
{asset 'app.js'}

{* Pré-carrega importações dinâmicas críticas *}
{preload 'components/chart.js'}

Isso informa ao navegador para baixar o componente do gráfico em segundo plano, para que esteja pronto imediatamente quando necessário.

Suporte a TypeScript

TypeScript funciona de imediato:

// assets/main.ts
interface User {
	name: string
	email: string
}

export function greetUser(user: User): void {
	console.log(`Hello, ${user.name}!`)
}

Referencie arquivos TypeScript normalmente:

{asset 'main.ts'}

Para suporte completo a TypeScript, instale-o:

npm install -D typescript

Configuração Adicional do Vite

Aqui estão algumas opções úteis de configuração do Vite com explicações detalhadas:

export default defineConfig({
	// Diretório raiz contendo os assets de origem
	root: 'assets',

	// Pasta cujo conteúdo é copido para o diretório de saída como está
	// Padrão: 'public' (relativo a 'root')
	publicDir: 'public',

	build: {
		// Onde colocar os arquivos compilados (relativo a 'root')
		outDir: '../www/assets',

		// Esvaziar o diretório de saída antes de construir?
		// Útil para remover arquivos antigos de construções anteriores
		emptyOutDir: true,

		// Subdiretório dentro de outDir para chunks e assets gerados
		// Isso ajuda a organizar a estrutura de saída
		assetsDir: 'static',

		rollupOptions: {
			// Ponto(s) de entrada - pode ser um único arquivo ou array de arquivos
			// Cada ponto de entrada se torna um bundle separado
			input: [
				'app.js',      // aplicação principal
				'admin.js',    // painel de administração
			],
		},
	},

	server: {
		// Host para o qual o servidor de desenvolvimento deve se vincular
		// Use '0.0.0.0' para expor à rede
		host: 'localhost',

		// Porta para o servidor de desenvolvimento
		port: 5173,

		// Configuração CORS para solicitações cross-origin
		cors: {
			origin: 'http://myapp.local',
		},
	},

	css: {
		// Habilitar sourcemaps CSS em desenvolvimento
		devSourcemap: true,
	},

	plugins: [
		nette(),
	],
});

É isso! Agora você tem um sistema de construção moderno integrado com Nette Assets.

versão: 1.0