- 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'
425 lines
9 KiB
Markdown
425 lines
9 KiB
Markdown
# 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](https://fresh.deno.dev)
|
|
- **Runtime**: [Deno 2.x](https://deno.land)
|
|
- **JavaScript Library**: [Preact 10](https://preactjs.com)
|
|
- **Estilização**: Tailwind CSS 3
|
|
- **Signals**: @preact/signals
|
|
|
|
## 📦 Instalação
|
|
|
|
### Pré-requisito: Deno
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```tsx
|
|
// routes/index.tsx
|
|
export default function Home() {
|
|
return (
|
|
<div>
|
|
<h1>Homepage</h1>
|
|
<p>Renderizado no servidor!</p>
|
|
</div>
|
|
);
|
|
}
|
|
```
|
|
|
|
Rotas dinâmicas:
|
|
```tsx
|
|
// 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:
|
|
|
|
```tsx
|
|
// 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
|
|
|
|
```tsx
|
|
// 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:
|
|
|
|
```tsx
|
|
// 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
|
|
|
|
```bash
|
|
deno task check
|
|
```
|
|
|
|
Executa:
|
|
1. `deno fmt --check` (formatação)
|
|
2. `deno lint` (linting)
|
|
3. `deno check **/*.ts` (type-check)
|
|
|
|
### Corrigir Formatação
|
|
|
|
```bash
|
|
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:**
|
|
|
|
1. **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
|
|
```
|
|
|
|
2. **Via CLI**:
|
|
```bash
|
|
# 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`:
|
|
|
|
```yaml
|
|
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)
|
|
|
|
```dockerfile
|
|
FROM denoland/deno:alpine
|
|
|
|
WORKDIR /app
|
|
COPY . .
|
|
RUN deno cache dev.ts
|
|
|
|
EXPOSE 8000
|
|
CMD ["deno", "task", "start"]
|
|
```
|
|
|
|
```bash
|
|
docker build -t core-landing .
|
|
docker run -p 8000:8000 core-landing
|
|
```
|
|
|
|
### Fly.io
|
|
|
|
```bash
|
|
flyctl launch
|
|
flyctl deploy
|
|
```
|
|
|
|
## ⚙️ Configuração Avançada
|
|
|
|
### Variáveis de Ambiente
|
|
|
|
Fresh carrega `.env` automaticamente (se existir):
|
|
|
|
```env
|
|
# landing/.env
|
|
API_URL=https://api.example.com
|
|
```
|
|
|
|
Acesso:
|
|
```typescript
|
|
const apiUrl = Deno.env.get("API_URL");
|
|
```
|
|
|
|
**⚠️ Segurança**: Não exponha secrets no client! Use apenas em API routes.
|
|
|
|
### Custom Middleware
|
|
|
|
```tsx
|
|
// 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:
|
|
|
|
```bash
|
|
# deno.json já inclui por padrão
|
|
DENO_TLS_CA_STORE=system deno task start
|
|
```
|
|
|
|
## 🔧 Troubleshooting
|
|
|
|
### "Import map not found"
|
|
|
|
**Solução**: Regenerar manifesto
|
|
```bash
|
|
deno task manifest
|
|
```
|
|
|
|
### Erro ao baixar dependências
|
|
|
|
**Solução**: Limpar cache
|
|
```bash
|
|
deno cache --reload dev.ts
|
|
```
|
|
|
|
### Port 8000 já em uso
|
|
|
|
**Solução**: Alterar porta em `dev.ts`
|
|
```typescript
|
|
await start(manifest, { port: 3000 });
|
|
```
|
|
|
|
### Tailwind não funciona
|
|
|
|
**Solução**: Verificar plugin em `fresh.config.ts`
|
|
```typescript
|
|
import twindPlugin from "$fresh/plugins/twind.ts";
|
|
|
|
export default {
|
|
plugins: [twindPlugin(twindConfig)],
|
|
};
|
|
```
|
|
|
|
## 📚 Recursos
|
|
|
|
- [Fresh Documentation](https://fresh.deno.dev/docs)
|
|
- [Deno Manual](https://deno.land/manual)
|
|
- [Preact Guide](https://preactjs.com/guide)
|
|
- [Islands Architecture](https://jasonformat.com/islands-architecture/)
|
|
|
|
## 🆚 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](../README.md).
|