- All SKILL.md files now <500 lines (avg reduction 69%) - Detailed content extracted to references/ subdirectories - Frontmatter standardised: only name + description (Anthropic standard) - New skills: brand-guidelines, spec-coauthor, report-templates, skill-creator - Design skills: anti-slop guidelines, premium-proposals reference - Removed non-standard frontmatter fields (triggers, version, author, category) Plugins affected: infraestrutura, marketing, dev-tools, crm-ops, gestao, core-tools, negocio, perfex-dev, wordpress, design-media Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
221 lines
4.7 KiB
Markdown
221 lines
4.7 KiB
Markdown
---
|
|
name: nextjs
|
|
description: Desenvolvimento Next.js moderno (13+) com App Router, Server Components, rotas API e deployment seguindo padroes Descomplicar.
|
|
---
|
|
|
|
# /nextjs - Next.js Development
|
|
|
|
Desenvolvimento Next.js moderno (13+) com App Router e Server Components.
|
|
|
|
---
|
|
|
|
## Contexto NotebookLM
|
|
|
|
```
|
|
mcp__notebooklm__notebook_query({
|
|
notebook_id: "24947ffa-0019-448a-a340-2f4a275d2eb1",
|
|
query: "<adaptar ao contexto do pedido>"
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## Regra #48 - Dev Container (OBRIGATÓRIO)
|
|
|
|
**TODOS os projectos Next.js devem ser desenvolvidos no container dev.**
|
|
|
|
```
|
|
SSH: server="dev" (mcp__ssh-unified__ssh_execute)
|
|
Path: /root/Dev/<projecto>
|
|
Sync: auto -> /media/ealmeida/Dados/Dev/<projecto> (Syncthing)
|
|
```
|
|
|
|
**Workflow:**
|
|
1. `mcp__ssh-unified__ssh_execute server:"dev" command:"mkdir -p /root/Dev/<projecto>"`
|
|
2. Desenvolver e testar no container
|
|
3. `npm run build` no container antes de deploy
|
|
4. Deploy via EasyPanel
|
|
5. Syncthing propaga automaticamente
|
|
|
|
**NUNCA:** `npx create-next-app` directamente no PC local para projectos colaborativos.
|
|
|
|
---
|
|
|
|
## App Router Structure
|
|
|
|
```
|
|
app/
|
|
├── layout.tsx # Root layout (obrigatório)
|
|
├── page.tsx # Home page
|
|
├── loading.tsx # Loading UI (Suspense)
|
|
├── error.tsx # Error boundary
|
|
├── not-found.tsx # 404 page
|
|
├── (auth)/ # Route group (não afecta URL)
|
|
│ ├── login/page.tsx
|
|
│ └── register/page.tsx
|
|
├── dashboard/
|
|
│ ├── layout.tsx
|
|
│ ├── page.tsx
|
|
│ └── [id]/page.tsx # Dynamic route
|
|
└── api/route.ts # API route
|
|
```
|
|
|
|
---
|
|
|
|
## Server vs Client Components
|
|
|
|
### Server Component (default)
|
|
|
|
```tsx
|
|
async function ProductsPage() {
|
|
const products = await db.product.findMany();
|
|
return <div>{products.map(p => <ProductCard key={p.id} product={p} />)}</div>;
|
|
}
|
|
```
|
|
|
|
### Client Component
|
|
|
|
```tsx
|
|
'use client';
|
|
import { useState } from 'react';
|
|
|
|
function Counter() {
|
|
const [count, setCount] = useState(0);
|
|
return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Data Fetching Patterns
|
|
|
|
```tsx
|
|
// Static (SSG) - default
|
|
const data = await fetch('https://api.example.com/data', { cache: 'force-cache' });
|
|
|
|
// Dynamic (SSR)
|
|
const data = await fetch('https://api.example.com/data', { cache: 'no-store' });
|
|
|
|
// ISR - revalidação automática
|
|
const data = await fetch('https://api.example.com/data', { next: { revalidate: 60 } });
|
|
```
|
|
|
|
---
|
|
|
|
## Server Actions
|
|
|
|
```tsx
|
|
// app/actions.ts
|
|
'use server';
|
|
import { revalidatePath } from 'next/cache';
|
|
|
|
export async function createPost(formData: FormData) {
|
|
const title = formData.get('title') as string;
|
|
await db.post.create({ data: { title } });
|
|
revalidatePath('/posts');
|
|
}
|
|
|
|
// Uso no form:
|
|
<form action={createPost}>
|
|
<input name="title" required />
|
|
<button type="submit">Create</button>
|
|
</form>
|
|
```
|
|
|
|
---
|
|
|
|
## Routing Avançado
|
|
|
|
### Middleware
|
|
|
|
```tsx
|
|
// middleware.ts
|
|
import { NextResponse } from 'next/server';
|
|
import type { NextRequest } from 'next/server';
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const token = request.cookies.get('token');
|
|
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
|
|
return NextResponse.redirect(new URL('/login', request.url));
|
|
}
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = { matcher: ['/dashboard/:path*'] };
|
|
```
|
|
|
|
---
|
|
|
|
## Optimizações
|
|
|
|
### Images
|
|
```tsx
|
|
import Image from 'next/image';
|
|
<Image src="/photo.jpg" width={500} height={300} alt="Photo" priority />
|
|
```
|
|
|
|
### Metadata (SEO)
|
|
```tsx
|
|
export const metadata = {
|
|
title: 'Home',
|
|
description: 'Home page',
|
|
openGraph: { title: 'Home', images: ['/og-image.jpg'] },
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## Performance (Prioridades)
|
|
|
|
| Prioridade | Categoria | Ganho |
|
|
|---|---|---|
|
|
| CRITICAL | Eliminar Waterfalls (Promise.all) | 2-10x latência |
|
|
| CRITICAL | Bundle Size (dynamic imports) | 200-800ms load |
|
|
| HIGH | Server-Side (auth actions, React.cache) | RSC payload |
|
|
| MEDIUM | Re-renders (derived state, functional setState) | Responsividade |
|
|
|
|
Para todas as 57 regras com exemplos de código: ver `references/performance-rules.md`
|
|
|
|
---
|
|
|
|
## Deployment
|
|
|
|
### Docker
|
|
|
|
```dockerfile
|
|
FROM node:18-alpine AS builder
|
|
WORKDIR /app
|
|
COPY package*.json ./
|
|
RUN npm ci
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
FROM node:18-alpine
|
|
WORKDIR /app
|
|
COPY --from=builder /app/.next ./.next
|
|
COPY --from=builder /app/public ./public
|
|
COPY --from=builder /app/package*.json ./
|
|
RUN npm ci --production
|
|
EXPOSE 3000
|
|
CMD ["npm", "start"]
|
|
```
|
|
|
|
---
|
|
|
|
## Datasets Dify
|
|
|
|
| Dataset | ID |
|
|
|---------|-----|
|
|
| Desenvolvimento de Software | `e7c7decc-0ded-4351-ab14-b110b3c38ec9` |
|
|
| TI | `7f63ec0c-6321-488c-b107-980140199850` |
|
|
|
|
---
|
|
|
|
## Referências
|
|
|
|
- `references/performance-rules.md` - 57 regras de performance com exemplos completos
|
|
|
|
---
|
|
|
|
*Versão 1.0.0 | Descomplicar®*
|