- Atualiza landing/README.md com configuração correta do Deno Deploy - Adiciona DENO_DEPLOY_FIX.md com troubleshooting detalhado - Explica que 'deno install' não existe e deve ser removido - Documenta valores corretos: Install command (vazio), Build Directory (landing) - Adiciona tabela comparativa Deno vs npm/yarn - Inclui workflow GitHub Actions opcional para CI/CD - Corrige erro: 'Executing install command - build failed'
9 KiB
Landing Page - Core Platform
Landing page desenvolvida com Fresh (framework Deno) e Tailwind CSS. Server-side rendering para performance máxima.
🎯 Visão Geral
Landing page pública da plataforma DevOps, com:
- Server-Side Rendering (SSR) nativo
- Componentes interativos (Islands Architecture)
- Páginas estáticas otimizadas
- Tailwind CSS integrado
🛠 Stack Tecnológica
- Framework: Fresh 1.7
- Runtime: Deno 2.x
- JavaScript Library: Preact 10
- Estilização: Tailwind CSS 3
- Signals: @preact/signals
📦 Instalação
Pré-requisito: Deno
# Linux/Mac
curl -fsSL https://deno.land/install.sh | sh
# Windows (PowerShell)
irm https://deno.land/install.ps1 | iex
# Verificar instalação
deno --version
Dependências
Fresh gerencia dependências automaticamente via deno.json. Não precisa npm install!
As dependências são baixadas na primeira execução:
cd landing
deno task start
🏃 Scripts
Todos os scripts estão definidos em deno.json:
| Comando | Descrição |
|---|---|
deno task start |
Inicia dev server (porta 8000) com hot reload |
deno task build |
Gera build de produção |
deno task preview |
Serve build de produção |
deno task check |
Executa fmt + lint + type-check |
deno task manifest |
Regenera arquivo de rotas |
Executar em Desenvolvimento
deno task start
Acesse: http://localhost:8000
Hot Reload: Alterações em routes/ e islands/ recarregam automaticamente.
📁 Estrutura de Pastas
landing/
├── routes/ # 🗺️ Rotas (SSR)
│ ├── index.tsx # Homepage (/)
│ ├── _app.tsx # Layout global
│ ├── _404.tsx # Página 404
│ ├── greet/
│ │ └── [name].tsx # Rota dinâmica (/greet/:name)
│ └── api/
│ └── joke.ts # API endpoint (/api/joke)
│
├── islands/ # 🏝️ Componentes interativos (client-side)
│ ├── Counter.tsx # Exemplo de contador
│ └── ServerStatus.tsx # Widget de status
│
├── components/ # 🧩 Componentes estáticos (SSR only)
│ ├── Button.tsx
│ └── Header.tsx
│
├── static/ # 📦 Arquivos estáticos
│ ├── logo.svg
│ ├── favicon.ico
│ └── styles.css
│
├── deno.json # Configuração Deno + tarefas
├── fresh.config.ts # Configuração Fresh
├── fresh.gen.ts # Auto-gerado (manifesto de rotas)
├── main.ts # Entry point produção
├── dev.ts # Entry point desenvolvimento
└── tailwind.config.ts # Configuração Tailwind
🏗️ Arquitetura Fresh
Routes (SSR)
Arquivos em routes/ são renderizados no servidor:
// routes/index.tsx
export default function Home() {
return (
<div>
<h1>Homepage</h1>
<p>Renderizado no servidor!</p>
</div>
);
}
Rotas dinâmicas:
// routes/greet/[name].tsx
export default function GreetPage(props) {
const { name } = props.params;
return <h1>Olá, {name}!</h1>;
}
Islands (Client-Side)
Componentes em islands/ são hidratados no cliente:
// islands/Counter.tsx
import { Signal, signal } from "@preact/signals";
export default function Counter() {
const count = signal(0);
return (
<div>
<p>Contador: {count}</p>
<button onClick={() => count.value++}>+1</button>
</div>
);
}
Quando usar Islands:
- Formulários interativos
- Widgets dinâmicos
- Animações client-side
Quando usar Routes:
- Conteúdo estático
- SEO crítico
- Performance máxima
API Routes
// routes/api/joke.ts
export const handler = {
GET() {
const joke = "Por que o JavaScript foi ao psicólogo? Porque tinha muitos callbacks!";
return new Response(JSON.stringify({ joke }), {
headers: { "Content-Type": "application/json" },
});
},
};
Acesse: http://localhost:8000/api/joke
🎨 Tailwind CSS
Fresh integra Tailwind via plugin:
// Usar classes normalmente
<div class="bg-blue-500 text-white p-4 rounded-lg">
Card estilizado
</div>
Configuração: tailwind.config.ts
🧪 Testes
Type Checking
deno task check
Executa:
deno fmt --check(formatação)deno lint(linting)deno check **/*.ts(type-check)
Corrigir Formatação
deno fmt
🚀 Deploy
Deno Deploy (Recomendado)
⚠️ IMPORTANTE - Configuração Correta:
No painel do Deno Deploy, configure:
| Campo | Valor Correto | ❌ Valor Incorreto |
|---|---|---|
| Build Directory | landing |
\landing |
| Install command | (deixe vazio) | deno install |
| Build command | deno task build |
✅ |
| Entrypoint | main.ts |
✅ |
Por que deixar Install command vazio?
O Deno não precisa de comando install! Ele baixa dependências automaticamente via deno.json (import maps). O comando deno install não existe e causa erro:
❌ Executing install command
deno install
Error: Command not found
Configuração Detalhada:
-
Via GitHub (automático):
1. Push para GitHub 2. Conecte repo em https://dash.deno.com 3. Configure: - Framework: Fresh - Build Directory: landing - Install command: (DEIXE VAZIO!) - Build command: deno task build - Root Directory: / (se o repo inteiro) 4. Deploy feito em cada push -
Via CLI:
# Instalar CLI deno install -Arf --global https://deno.land/x/deploy/deployctl.ts # Deploy direto cd landing deployctl deploy --project=seu-projeto main.ts
Arquivo de configuração (opcional):
Crie landing/.github/workflows/deploy.yml:
name: Deploy to Deno Deploy
on:
push:
branches: [main]
paths:
- 'landing/**'
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Setup Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.x
- name: Build
run: |
cd landing
deno task build
- name: Deploy to Deno Deploy
uses: denoland/deployctl@v1
with:
project: seu-projeto
entrypoint: landing/main.ts
root: landing
Docker (Self-Hosted)
FROM denoland/deno:alpine
WORKDIR /app
COPY . .
RUN deno cache dev.ts
EXPOSE 8000
CMD ["deno", "task", "start"]
docker build -t core-landing .
docker run -p 8000:8000 core-landing
Fly.io
flyctl launch
flyctl deploy
⚙️ Configuração Avançada
Variáveis de Ambiente
Fresh carrega .env automaticamente (se existir):
# landing/.env
API_URL=https://api.example.com
Acesso:
const apiUrl = Deno.env.get("API_URL");
⚠️ Segurança: Não exponha secrets no client! Use apenas em API routes.
Custom Middleware
// routes/_middleware.ts
export async function handler(req, ctx) {
console.log("Request:", req.url);
const resp = await ctx.next();
resp.headers.set("X-Custom-Header", "Fresh");
return resp;
}
DENO_TLS_CA_STORE=system
Se sua rede usa certificados customizados:
# deno.json já inclui por padrão
DENO_TLS_CA_STORE=system deno task start
🔧 Troubleshooting
"Import map not found"
Solução: Regenerar manifesto
deno task manifest
Erro ao baixar dependências
Solução: Limpar cache
deno cache --reload dev.ts
Port 8000 já em uso
Solução: Alterar porta em dev.ts
await start(manifest, { port: 3000 });
Tailwind não funciona
Solução: Verificar plugin em fresh.config.ts
import twindPlugin from "$fresh/plugins/twind.ts";
export default {
plugins: [twindPlugin(twindConfig)],
};
📚 Recursos
🆚 Fresh vs Outros Frameworks
| Feature | Fresh | Next.js | SvelteKit |
|---|---|---|---|
| Runtime | Deno | Node.js | Node.js |
| SSR | ✅ Nativo | ✅ | ✅ |
| Islands | ✅ Automático | ❌ | ❌ |
| Bundle size | 0 KB default | ~70 KB | ~20 KB |
| TypeScript | ✅ Nativo | Precisa config | Precisa config |
| Deploy | Deno Deploy | Vercel | Vercel/Netlify |
Vantagens Fresh:
- Zero JavaScript no cliente por padrão
- TypeScript sem configuração
- Deploy instantâneo (Deno Deploy)
- Deno = segurança e performance
Para configuração completa do monorepo, veja o README principal.