nextjs
Next.js 16 — Arquitectura Avanzada y Patrones Modernos
1. Arquitectura Interna del Runtime en Next.js 16
Next.js 16 consolida varios runtimes:
- Node.js Runtime
- Ideal para lógica pesada, conexiones largas, ORMs, colas, workers.
- Edge Runtime
- Para lógica superligera, caché global, auth tokens, A/B testing.
- Web Runtime
- Código del cliente y server components en build.
Selección del runtime (patrón recomendado)
- Colocar en server actions la mutación + validación.
- Colocar lógica global de auth en proxy.ts (antes middleware).
- Procesamiento intensivo ⇒ Node.js Runtime.
- Respuestas micro-cacheadas ⇒ Edge Runtime.
Referencia oficial:
2. Patrón “Front + Actions + Services”
Patrón moderno para aplicaciones grandes:
2.1 Componentes (UI)
- Server/Client components.
- Minimizar client components (coste en bundle + hydration).
2.2 Server Actions
- Validación, mutaciones, persistencia.
- Desacoplarlos del UI exportando funciones puras.
2.3 Capa de Servicios
- Clases o funciones puras donde vive la lógica de dominio.
- Útil para:
- Testing
- Reutilización cross-rutas
- Microservicios híbridos
Ejemplo:
// app/actions/create-user.ts
'use server'
import { userService } from '@/services/user-service'
export async function createUser(data) {
return userService.create(data)
}
`
3. Arquitectura de Datos en Next.js 16
El modelo recomendado para 2025:
3.1 Acceso a DB con Runtimes Múltiples
- Node.js Runtime para ORMs: Prisma, Drizzle, Kysely.
- Edge Runtime con:
- PlanetScale
- Neon (Postgres serverless)
- Upstash Redis
- LibSQL/Turso
3.2 Capa de Caché Multinivel
- Caché declarativa (
use cache) - Revalidaciones granulares (
revalidateTag,revalidatePath) - Edge caché con Vercel Edge
3.3 Streaming de Datos (React 19 + Next 16)
- Ideal para feeds, dashboards, reporting
- Mantiene TTFB bajo
4. Arquitectura de Rutas y Dominios de Contexto
Patrón recomendado para proyectos grandes en App Router:
/app
(auth) → layouts y acciones de autenticación
(dashboard)
analytics/
billing/
users/
api/…
Principios:
- Rutas agrupadas por contexto, no por tipo de archivo.
- Cada grupo con su propio layout + loading + error.
- Servicios compartidos debajo de
/libo/services.
5. Edge Patterns Modernos en Next.js 16
Next 16 mejora el modelo de proxy.ts, que centraliza el “network boundary”:
Casos recomendados:
- Rate limiting
- Token refresh
- Redirecciones inteligentes
- Internationalización basada en geolocalización
- A/B testing + Feature flags
Documentación base:
6. Renderización Estratégica (SSR + ISR + PPR)
Next.js 16 habilita estrategias más granulares:
6.1 SSR Híbrido con Server Actions
- Uso para dashboards con datos frescos.
6.2 ISR + revalidateTag
- Revalidación selectiva según dominios de datos.
- Ideal para ecommerce, blogs, contenido masivo.
6.3 PPR (Partial Pre-Rendering)
- Divide página en fragmentos precalculados + runtime.
- Reduce TTFB y coste dinámico.
7. Colas, Jobs y Procesamiento Asíncrono
Next.js 16 funciona con colas externas usando Server Actions:
Patrones comunes
- Webhooks + Server Actions
- Colas:
- Inngest
- Trigger.dev
- Upstash Queues
Buenas prácticas
- Delegar trabajos pesados a workers
- No bloquear server actions
- Cachear resultados intermedios con tags
8. Observabilidad, Logging y Monitorización
Moderna arquitectura para producción:
Recomendado en Next.js 16
- Vercel Observability Layer
- Logging estructurado con Pino
- Trazas distribuidas (OpenTelemetry integrado)
- Uso de
server-timingheaders y analítica nativa
Docs:
9. Arquitectura de CI/CD y Contenedores
9.1 CI/CD
- Tests en server actions
- Pruebas de rutas
route.js - Bundling con Turbopack en CI para detectar fallos
9.2 Contenedores
Patrón recomendado para Next.js 16:
- Build multi-stage (Node 20+)
- Adaptar runtime detectado por Next para evitar errores edge/node.
10. DX Avanzado: Monorepos, Workspaces y Generadores
Monorepo con Turborepo
- Capa de servicios compartidos
- Reutilización de UI components en librerías internas
Generadores modernos
- Plop.js
- Hygen
- Create fuzzy-templates para scaffolding
11. Seguridad 2025 en Next.js 16
- Protección de Server Actions (validación estricta)
- Sanitización con Zod o Valibot
- Tokens firmados en Edge Runtime
- Cabeceras de seguridad automáticas en Vercel
- Autorización contextual por layout/routes
12. Lista de Recursos (formato Obsidian)
- Next.js 16 Overview
- Next.js Runtime Options
- Next.js Middleware / Proxy
- React 19 + Server Actions Reference
Apuntes Next.js 16 — Arquitectura y Fundamentos
1. Panorama General de Next.js 16
- Next.js 16 introduce mejoras en rendimiento, DX y caché explícita.
- Anuncio oficial:
2. Bundler: Turbopack por Defecto
- Turbopack ahora es el bundler oficial:
- Builds hasta 5× más rápidas
- HMR hasta 10× más rápido
- Recursos:
3. Caché Explícita con Cache Components
Next.js 16 introduce un sistema de caché manual y predecible, basado en componentes cacheables con una directiva especial:
'use cache'
`
Activación
const nextConfig = {
cacheComponents: true,
}
export default nextConfig
Recursos oficiales
Nuevas APIs relacionadas
revalidateTag()- Rovidx – Next 16 New Features
updateTag()- Next.js 16 Performance Overview
4. Enrutamiento y Prefetching Mejorados
- Mejoras en tiempos de navegación y deduplicación de layouts.
- Prefetch inteligente basado en heurísticas.
- Recursos:
5. Reemplazo de middleware.ts → proxy.ts
- Nuevo archivo
proxy.tsque sustituye amiddleware.ts. - Modelo más claro basado en “network boundary”.
-
Recursos:
6. Next.js DevTools MCP
- Nueva integración con el estándar Model Context Protocol (MCP).
-
Permite a agentes/AI acceder a:
- info del proyecto
- rutas
- estado del build
- logs
-
Recurso:
7. Mejoras en Server Actions
- Rendimiento optimizado.
- Menos sobrecarga en el servidor.
- Mutaciones más rápidas.
- Integración con caché y PPR.
-
Recurso:
8. Partial Pre-Rendering (PPR)
- Sistema híbrido:
- partes renderizadas estaticamente
- partes que se resuelven bajo demanda
- Reduce TTFB y mejora caché granular.
-
Recurso:
9. Mejoras DX (Developer Experience)
- Turbopack Dev Server más estable.
- Errores con stacktrace mejorado.
- Renderizado más consistente entre server/client.
-
Recurso:
10. Resumen de Cambios Clave en Next.js 16
- Turbopack por defecto → velocidades enormes.
- Caché explícita con
use cache. - Sistema de tags para revalidación manual.
- Nuevo
proxy.tsreemplazamiddleware.ts. - DevTools integrados con MCP.
- Mejoras en enrutamiento y prefetch.
- PPR más estable y eficiente.
- Server Actions más rápidas.
11. Lecturas Recomendadas
- Next.js 16 – Release Notes
- Next.js 16 Beta – Technical Breakdown
- Deep Dive: Performance & Caching
- Next.js 16: New Features Summary
Apuntes Next.js 14 — Arquitectura, Fundamentos y Recursos
1. Introducción a Next.js
Next.js es un framework React moderno optimizado para:
- Renderizado híbrido (SSR, SSG, ISR)
- Server Components por defecto
- Server Actions
- Rutas avanzadas con App Router
- Optimizaciones automáticas
- Integración profunda con Vercel
2. Comandos Esenciales
- Crear proyecto:
npx create-next-app@latest
```
---
## 3. Plantillas y Ejemplos Oficiales
### 3.1 Repositorio de ejemplos
- [ ] [Next.js examples — GitHub](https://github.com/vercel/next.js/tree/canary/examples)
### 3.2 Plantillas de Vercel
- [MongoDB Starter](https://vercel.com/templates/next.js/mongodb-starter)
- [Tailwind Blog Starter](https://vercel.com/templates/next.js/tailwind-css-starter-blog)
- [Más plantillas Next + Tailwind](https://vercel.com/templates/tailwind)
---
## 4. Starters y Boilerplates útiles
- [Relivator Next.js Starter (revalidator)](https://github.com/blefnk/relivator-nextjs-starter)
- [Sass Starter (Rapidlaunch)](https://github.com/alifarooq9/rapidlaunch)
---
## 5. [Testing](/testing/testing/) en Next.js
- Test unitarios con React Testing Library, Jest o Vitest
---
## 6. Fundamentos y Conceptos Modernos de Next.js
### 6.1 Server Components
- Renderizados en el servidor por defecto.
- Evitan enviar JS al cliente salvo cuando se usa `"use client"`.
### 6.2 Server Actions
- Acceso a:
- cookies
- headers
- mutaciones en server
- múltiples acciones en un mismo formulario
- revalidación automática
- Integración sencilla con formularios.
### 6.3 Hooks Modernos recomendados
- `useTransition` → para estados concurrentes.
- `useReducer` → estados complejos.
- Evitar el uso excesivo de `useEffect`.
### 6.4 Buenas prácticas
- Priorizar **Server Components**.
- Evitar fetch en el cliente salvo necesario.
- Reducir estados globales (usar server actions + fetch).
- Integración simple con Firebase, Prisma, Convex, etc.
---
## 7. Plantillas y Ejemplos Destacados
### 7.1 E-commerce con Next.js
- [Next Amazona v2 (Next eCommerce)](https://github.com/basir/next-amazona-v2)
### 7.2 Blog con MongoDB
- [Next Blog — Repo completo](https://github.com/safak/next-blog/tree/completed)
- [Diagrama arquitectura DB](https://app.eraser.io/workspace/aSshPSKlaKr8XiddBdlv)
### 7.3 Clones de Notion (Next.js + Prisma + Tailwind)
- https://github.com/aafrzl/nextion
- https://github.com/abdallaamin/jotion
- https://github.com/konstantinmuenster/notion-clone
- https://github.com/dj1samsoe/notion-clone
### 7.4 App Threads Clone
- [Repo oficial (adrianhajdin)](https://github.com/adrianhajdin/threads)
### 7.5 App Gestor de Contraseñas — Next 14 + PWA
- [GitHub tarredev-password](https://github.dev/ratasi/tarredev-password)
- Incluye:
- autenticación
- rutas protegidas
- Prisma + DB
- PWA
---
## 8. Integraciones y Stacks útiles con Next.js
- **Convex + Tailwind + React + Next.js**
- Uso recomendado para BaaS reactivo.
- **Firebase (Auth, Firestore, Storage)**
- **Prisma ORM + PlanetScale / Neon / Supabase**
- **Auth.js (NextAuth)** para autenticación moderna.
## 9. Recursos
- [Next.js Official Learn — Foundations](https://nextjs.org/learn/foundations/about-nextjs/what-is-nextjs)
- NEXT.JS COOKBOOK
- NEXT.JS COOKBOOK > Introduction
# Curso de Next 13 (2023)
## Netflix Clone 🎈
- [github nextflix](https://github.com/rajput-hemant/nextflix)
- Tecnologías usadas: framer motion, authentication, css modules, ISR, login sin password, GraphQL, authentication SDK Hasura, deploy en Vercel
- Integración avanzada con animaciones, optimización de UI/UX y pipelines de despliegue
## Coffee Shop App ✔
- npx: instalación temporal, prueba de paquetes, npm vs npx — ¿Cuál es la Diferencia-
- Guías de actualización:
- [guia de actualizaciones de next](https://nextjs.org/docs/pages/building-your-application/upgrading)
- `npm audit`, `npm audit fix`, `npm install next@latest`
- [webpack 5](https://nextjs.org/docs/messages/webpack5)
- `--force`, actualizar react y react-dom
- [github coffee store](https://github.com/BernieTv/Coffee-Connoisseur/blob/main/pages/index.js)
- Localizador de stores de café
- Workspace:
## Features
### Tecnologías
- Node.js, SEO, Static Site Generation, Server Side Rendering, Incremental Site Regeneration
- Hydration, Serverless Functions, Airtable, SWR, React Hooks
- React 18, [react server components](https://nextjs.org/docs/app/building-your-application/rendering/server-components)
- Server side streaming: [loading ui and streaming](https://nextjs.org/docs/app/building-your-application/routing/loading-ui-and-streaming)
- ES Modules, importación desde CDNs
- [ISR](https://nextjs.org/docs/pages/building-your-application/data-fetching/incremental-static-regeneration): revalidate, fallback
- Edge functions, Using Next.js’ middleware and Edge Functions - LogRocket Blog, [edge runtime api](https://www.framer.com/motion/)
- Comparación: Next.js vs Create React App
- SWC compiler, *websockets*
### Middleware
- Configuraciones entre API call y request
- Autenticación, protección de bots, redirects/rewrites, soporte para navegadores antiguos
- Flags, tests A/B, analítica, logging
- `pages/_middleware.js`
- Middleware API
### Serverless Functions
- Guardar credenciales en el lado del servidor
- API key, carpeta `/api`
- Funcionan bajo demanda: el servidor se enciende al recibir un request
### Entry Point: `_app`
- Componentes compartidos globalmente
- Afecta el body
- Cabezal con `<Head>` separado es posible
### Rendimiento
- Code splitting, `next build`, chunks
- Minificación sin necesidad de webpack
- Image optimization: carga lazy
- Prefetching de assets
### SEO
- Metadata, bots
- `<Head>` component
- Ranking, crawling, indexing
- Meta tags, alt en imágenes, semántica HTML
- Análisis de base de datos para contenido dinámico
### Renderizado y Data Fetching
#### Static Site Generation (SSG)
- Generación en build time
- Static data + external API
- Data almacenada en CDN
- `getStaticProps`
#### Server Side Rendering (SSR)
- Generado en cada request
- `getServerSideProps`
- Ideal para data que cambia rápido (ej: news feed)
#### Incremental Static Regeneration (ISR)
- Mezcla SSG + SSR
- Intervalos de regeneración
- Primera request stale, segunda fresh
- `getStaticProps` con `revalidate`
#### Client Side Rendering (CSR)
- Render con React en el cliente
- Prerender parcial + data fetching client
- [client side fetching](https://nextjs.org/docs/pages/building-your-application/data-fetching/client-side)
- Ideal para dashboards
#### Pre-rendering y Hydration
- HTML estático previo a React
- Bots y SEO
- Server rendering previo a hydration
### Routing
- File-system routing
- History API
- Rutas:
- `index.js`: ruta raíz
- Nested routes
- Dynamic routes: `[id].js`
- `import { useRouter } from 'next/router'`
- Router query object
- Linking:
- `next/link` — [link component](https://nextjs.org/docs/pages/api-reference/components/link)
- Prop `scroll`: diferencias entre rutas dinámicas y no dinámicas
- API folder: backend logic + SSR
## Intro Componentes
- [x] [video curso](https://www.bilibili.com/video/BV1Um4y187Mz/?spm_id_from=333.337.search-card.all.click)
- [x] [video curso 2](https://www.bilibili.com/video/BV1Gc411N7ft/?spm_id_from=333.788.recommend_more_video.0)
- [x] [video cuso 3](https://www.bilibili.com/video/BV1Ss4y1M7HS/?p=11&spm_id_from=pageDriver)
- [ ] [video curso 4](https://www.bilibili.com/video/BV1Bs4y1M7nR/?spm_id_from=333.999.0.0)
- [ ] [video curso 5](https://www.bilibili.com/video/BV1Gh411F7BA/?spm_id_from=333.788.recommend_more_video.1)
- [x] crear app con next API y wireframe 🔺
- [ ] editar página 404 personalizada
- [ ] footer component
- [ ] fondo con [gradiente](https://meshgradient.com/)
- [ ] componente banner:
- Props: buttonText, handleOnClick → `handleOnBannerBtnClick`
- Head component de Next
- useRouter: [next useRouter](https://nextjs.org/docs/pages/api-reference/functions/use-router)
- `next/link`
- `next/image`: [image component](https://nextjs.org/docs/pages/api-reference/components/image)
- [ ] Añadir fuentes:
- En `_document.js` usando `<Head>`
- Extender document model: [custom document](https://nextjs.org/docs/pages/building-your-application/routing/custom-document)
- [Font Optimization](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts)
- [ ] card component:
- Props dinámicas `name` y `href`
### Otros y Refactor
- Condiciones de render: `stores.length > 0 &&`
- Error al acceder al JSON: nested arrays
- Destructuring y fallback: `router.fallback`
- Generación de paths dinámicos:
- `{ params: { id: coffeeStore.id.toString() }}`
- Función de voto: `{handleUpVoteButton}`
- `/lib` directory:
- `fetchCoffeeStores()`
- `getUrlForCoffeeStores(latLong, 'coffee stores', limit)`
- Fetch para obtener ID de API
- `async` en `getStaticPaths`
- Fallback de imágenes:
- `imgUrl={coffeeStore.imgUrl || 'url'}`
## CSS Confs
- CSS variables: `--var`, declarar en `:root {}`
- Mobile first, media queries, breakpoints
- [ ] Layout home con grid:
- [CSS-Guia completa > 13-CSS Grid](/uncategorized/css-guia-completa/#13-css-grid)
- columnas, containers, cardLayout
- Generar CSS tipo glass: [css glass generator](https://ui.glass/generator/)
- Clases CSS dinámicas que no colisionan
- Combinar clases con classNames:
- `import cls from "classnames"`
- Icons SVG desde [google fonts icons](https://fonts.google.com/icons)
## getStaticProps
- [ ] [getStaticProps](https://nextjs.org/docs/pages/building-your-application/data-fetching/get-static-props)
- Recibir props en **Home** desde el servidor.
- Guardar contenido de cada card en la CDN; posible integrar una API.
- Devuelve **static data**.
- Usado en rutas dinámicas: ``[id].js``.
- Props como key/value; la key suele ser el **id**.
- Se ejecuta **solo en el servidor**, nunca en el cliente.
- Corre en **build time**, excepto en dev mode que corre en client/server.
- Devolver data como props y usar ``find()``:
- Comparar un id dinámico con ``params.id``.
- Convertir ``store.id`` mediante ``toString()``.
- ``useRouter()`` para acceder al id: ``router.query.id``.
- Usar ``params`` directamente o desde ``staticProps.params``.
### Ejemplo getStaticProps
```js
export async function getStaticProps(context) {
const { params } = context;
const stores = await fetchStores();
const store = stores.find((s) => s.id.toString() === params.id);
return {
props: {
coffeeStore: store || null,
},
};
}
`
getStaticPaths
- getStaticPaths
- Genera páginas estáticas para rutas dinámicas.
- Define los paths prerenderizados.
- Solo se exporta en pages dinámicas.
- Se usa junto con getStaticProps.
- Solo corre en build time.
- Devuelve array de paths y un fallback.
fallback key
- fallback: false
- Si la ruta no existe → 404.
- fallback: true
- Descarga la página bajo demanda.
- Útil para muchas rutas.
- Si el
find()devuelve undefined → error en carga. - router.fallback == true
- Indica que la página está generándose.
Ejemplo getStaticPaths
export async function getStaticPaths() {
const stores = await fetchStores();
const paths = stores.map((store) => ({
params: { id: store.id.toString() },
}));
return {
paths,
fallback: true,
};
}
Obtener data de JSON o APIs
- Usar id en href para rutas dinámicas.
- Importar JSON y mapear contenido.
- Configurar dominio de imágenes en
next.config.js.
API Foursquare
- Foursquare Docs
- Place Search API para localizar stores.
- Query de tiendas por coordenadas.
- Limitar resultados + control de rate limiting.
- Integrar en
getStaticPropscomo función async: fetch(url, options)response.json()props: { coffeeStores: data.results }
Variables de entorno
- Environment variables
- Guardar keys en
process.env. - En options:
Authorization: process.env.NEXT_PUBLIC_FOURSQUARE_API_KEY
API Unsplash
- Unsplash API
- Obtener imágenes dinámicas para cada store.
- SDK: https://github.com/unsplash/unsplash-js
- Función
search.getPhotos(). - Keys en env.
- Mapear urls e integrarlas en
fetchCoffeeStores. - Condicionales:
- Si neighborhood vacío →
'' - Si imgUrl vacía →
null
Buscar tiendas cercanas — geolocation API
- Geolocation API
- Crear hook:
useTrackLocation. - Obtener lat/long del usuario.
- Solicitar permisos.
- Manejar errores y estado:
isFindingLocationsetLocationErrorMsg('')
Ejemplo Hook
const useTrackLocation = () => {
const [latLong, setLatLong] = useState('');
const [errorMsg, setErrorMsg] = useState('');
function success(position) {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
setLatLong(`${latitude},${longitude}`);
setErrorMsg('');
}
function error() {
setErrorMsg('No se pudo obtener la ubicación');
}
return { latLong, errorMsg };
};
Context y Reducer
- fetch async a
fetchCoffeeStorescon limit. - useEffect + try/catch en Home.
- Crear state global con Context API.
- En env usar
NEXT_PUBLIC_. [coffeeStores, setCoffeeStores]para stores cercanas.- Extraer desde context:
const { coffeeStores, latLong } = state - Manejar errores:
coffeeStoresError- Problemas con props estáticas en
[id].js+ fallback. - fallback false garantiza 404 si no existe store.
Context API
- Using React Context for State Management with Next.js
StoreProvideren_app.js.- Proveer:
<StoreContext.Provider value=>
Reducer
- Extracting State Logic into a Reducer – React
- Manejo de múltiples estados.
ACTION_TYPESpara dispatch.storeReduceraplica cambios via payload.
Ejemplo Reducer
export const storeReducer = (state, action) => {
switch (action.type) {
case ACTION_TYPES.SET_LAT_LONG:
return { ...state, latLong: action.payload.latLong };
case ACTION_TYPES.SET_COFFEE_STORES:
return { ...state, coffeeStores: action.payload.coffeeStores };
default:
return state;
}
};
Data no prerenderizada + fallback en [id].js
- Combinar props estáticas + context + SWR (opcional).
- Acceder al id:
const { id } = router.query - Obtener stores:
const { state: { coffeeStores } } = useContext(StoreContext) - Usar
initialProps. - Comprobar en useEffect:
- Si hay stores.
- Si initialProps está vacío → usar context.
- async
handleCreateCoffeeStorepara crear store en DB si no existe.
Declarar props de store
const { id, name, voting, imgUrl, neighbourhood, address } = coffeeStore;
Dependencias del useEffect
[id, initialProps.coffeeStore, coffeeStores, initialProps]
Utilidad isEmpty
- Crear
utils/index.js. - Comprobar si un objeto no tiene keys.
- Usado para decidir si usar fallback o props estáticas.
Código isEmpty
export const isEmpty = (obj) => {
return Object.keys(obj).length === 0;
};
Evitar circular dependencies
- Guardar context en carpeta dedicada:
store-context.js. - Importar solo desde
_app.jso componentes que lo usen.
API Routes y Serverless Functions
- API Routes
- Arquitectura híbrida: server-side + client-side en el mismo proyecto.
- Directorio:
/pages/api/*.js→ código backend dentro de Next. - Cada file exporta una única función como
export default. - Firma estándar:
export default function handler(req, res) {
res.status(200).json({ message: 'OK' });
}
```
- El archivo define la **ruta dinámica**:
- ``pages/api/coffee-store.js`` → ``/api/coffee-store``
- ``pages/api/[slug].js`` → rutas capturadas automáticamente.
- ``pages/api/[...slug].js`` → capturar *todas las rutas* (catch-all).
- Orden de prioridades del enrutado basado en el filesystem.
### REST y métodos HTTP
- GET → obtener recursos.
- POST → crear.
- PUT → actualizar.
- DELETE → eliminar.
- La forma final de la API depende de la ruta definida en el filesystem.
### Serverless Functions
- Lambdas ejecutadas bajo demanda (Vercel / Netlify).
- Infraestructura manejada por el proveedor.
- Timeout, cold starts, rate limits.
- Ideal para:
- Ops ligeras.
- Integración a DBs o APIs externas.
- Auth + operaciones CRUD.
---
## Obtener stores por geolocación usando API Routes
- Crear endpoint: ``/api/getCoffeeStoresByLocation``.
- Reutilizar ``fetchCoffeeStores`` dentro de la API route.
- Ejemplo:
```js
const getCoffeeStoresByLocation = async (req, res) => {
try {
const { latLong, limit } = req.query;
const stores = await fetchCoffeeStores(latLong, limit);
res.status(200).json(stores);
} catch (error) {
res.status(500).json({ message: 'Error fetching', error });
}
};
```
- **Importante**: si no se hace ``return`` o ``res.end()`` → la función se queda pendiente.
### Llamar a la API en Home con useEffect
```js
const fetchedCoffeeStores = await fetch(
`/api/getCoffeeStoresByLocation?latLong=${latLong}&limit=30`
);
const data = await fetchedCoffeeStores.json();
setCoffeeStores(data);
setCoffeeStoresError('');
`
Integración con getStaticProps
- Añadir
fetchCoffeeStorespara cargar data inicial. - Next permite ejecutarlo en servidor en build:
const coffeeStores = await fetchCoffeeStores();
return { props: { coffeeStores } };
Arquitectura + Persistencia en Airtable
- CSR: obtener stores cercanas vía API Routes.
- SSG: stores por ciudad pre-generadas.
- Flujo mixto:
- SSG carga stores iniciales.
- Context transmite la data.
- Airtable persiste cada store si no existe.
- Problema: al refrescar, el context se pierde → usar DB.
Configuración de Airtable
- Crear base:
- id (string)
- name
- voting (number)
- address
- neighbourhood
- Docs:
- https://airtable.com/developers/web/api/introduction
- https://github.com/Airtable/airtable.js
- Variables:
- API key
- Base ID
- En
.env.local:AIRTABLE_API_KEY=...
AIRTABLE_BASE_ID=...
Crear Coffee Store (POST)
- Endpoint:
/api/createCoffeeStore - Pasos:
- Leer
req.method - Validar
req.body - Buscar si existe ID con
findRecordByFilter - Crear si no existe
- Minificar resultado
- Leer
const records = await table.create([
{
fields: {
id,
name,
voting: voting || 0,
address: address || '',
neighbourhood: neighbourhood || '',
},
},
]);
Minificación de registros
const getMinifiedRecord = (record) => ({
recordId: record.id,
...record.fields,
});
const getMinifiedRecords = (records) => {
return records.map(getMinifiedRecord);
};
Usar Postman para probar
- GET:
/api/getCoffeeStoreById?id=123 - POST:
/api/createCoffeeStore - PUT:
/api/favouriteCoffeeStoreById(para votar)
Integración en [id].js
- Componentes manejan data combinada:
- initialProps (SSG)
- Context (CSR)
- Airtable DB
Flujo createCoffeeStore en frontend
const handleCreateCoffeeStore = async (coffeeStore) => {
try {
const res = await fetch('/api/createCoffeeStore', {
method: 'POST',
body: JSON.stringify({
...coffeeStore,
neighbourhood: coffeeStore.neighbourhood || '',
}),
});
await res.json();
} catch (error) {}
};
- Asegurar que IDs son strings.
- Señal: votos no incrementan con SSG → depende de la DB.
SWR — Stale While Revalidate
- https://swr.vercel.app/es-ES
- Sincronizar votaciones entre UI y DB.
- Soluciona actualización asíncrona + cache.
Implementación SWR
- Hook:
const { data, error } = useSWR(
`/api/getCoffeeStoreById?id=${id}`,
fetcher
);
- useEffect escucha cambios:
useEffect(() => {
if (data && data.length > 0) {
setCoffeeStore(data[0]);
setVotingCount(data[0].voting);
}
}, [data]);
- Si error → mostrar mensaje.
### Upvote (PUT)
- Endpoint:
/api/favouriteCoffeeStoreById - Lógica:
- Validar ID
- Buscar registro con
findRecordByFilter - Incrementar voto:
const calculateVoting = parseInt(record.voting) + 1;
```
4. Actualizar:
```js
const updateRecord = await table.update([
{
id: record.recordId,
fields: { voting: calculateVoting },
},
]);
```
5. Devolver minificado
### Efecto colateral
- La app genera nuevos inserts cuando encuentra stores cercanas desde Foursquare → se escriben en Airtable.
---
## Deploy: Vercel + Netlify
### Build
- ``npm run build`` → ``next build``
- ``next start`` → producción local
- Output con iconos para saber si las páginas son:
- SSG
- ISR
- SSR
### Vercel
- Deploy automático con Git.
- Logs de serverless functions.
- Envs separadas para dev/prod.
- CDNs sirven las páginas pre-generadas.
### Netlify
- Next.js plugin automático.
- Serverless functions soportadas.
- Imagenes:
- Requiere configuración extra si Next < 13.5
- ``next.config.js``:
```js
images: {
domains: ['images.unsplash.com'],
}
```
- Si falla → usar ``<img />`` HTML en vez de ``next/image``.
### Optimizaciones
- Comprobar con Pagespeed / Lighthouse.
- Asegurar:
- ``alt`` en imágenes.
- ``<Head>`` con metas por página.
- Meta description dinámica.
---
## Coffee Store — Snippets útiles
- `const Footer = () => {`
- `export default function Post({ postData, allPostsData }) {}`
- `import Document, { Html, Head, Main, NextScript } from 'next/document'`
- `class MyDocument extends Document {}`
- `className={cls("glass", styles.container)}`
- `module.exports = { images: { domains: ['...'], } }`
- `const getListOfCoffeeStorePhotos = async () => {}`
- `return unsplashResults.map(r => r.urls['small'])`
- `const [locationErrorMsg, setLocationErrorMsg] = useState('')`
- `const [isFindingLocation, setIsFindingLocation] = useState(false)`
- `const [coffeeStore, setCoffeeStore] = useState(initialProps.coffeeStore)`
- Airtable utils:
- `const table = base('coffee-stores');`
- `const findRecordByFilter = async (id) => {}`
- `const createRecords = await table.create([ ... ])`
- `return records.map(getMinifiedRecord)`
- `const { id, name, neighbourhood, address, imgUrl, voting } = req.body`
# Omnivore Nextjs
```base
type: list
name: "Notas con #nextjs en Omnivore"
order:
- property: date_saved
direction: desc
columns:
- file.name
- date_saved
filters:
and:
- file.inFolder("Omnivore")
- file.hasTag("nextjs")
views:
- type: table
name: Table
sort:
- property: file.mtime
direction: DESC
Omnivore React
type: list
name: "Notas con #react en Omnivore"
order:
- property: date_saved
direction: desc
columns:
- file.name
- date_saved
filters:
and:
- file.inFolder("Omnivore")
- file.hasTag("react", "React")
views:
- type: table
name: Table
order:
- file.name
- source_domain
sort:
- property: file.mtime
direction: DESC
Omnivore next js highlights
// Configuraciones
const tagName = "nextjs";
const headName = "Highlights";
// Crear un array para almacenar las páginas que contienen el tag "nextjs"
let pagesWithNextjs = [];
// Filtrar y recopilar las páginas que tienen el tag "nextjs"
dv.pages('"Omnivore"').forEach(page => {
if (page.tags && page.tags.includes(tagName)) {
pagesWithNextjs.push(page);
}
});
// Ordenar las páginas por 'date_saved' en orden descendente
pagesWithNextjs.sort((a, b) => {
return b.date_saved.localeCompare(a.date_saved);
});
// Iterar sobre cada página filtrada y ordenada
for (const page of pagesWithNextjs) {
const content = await dv.io.load(page.file.path);
const lines = content.split('\n');
let output = [];
let insideHead = false;
// Recorrer cada línea del contenido
for (const line of lines) {
if (line.startsWith("## " + headName)) {
insideHead = true;
} else if (line.startsWith("# ") && insideHead) {
insideHead = false;
break; // Salir del bucle cuando se encuentra el próximo encabezado
} else if (insideHead) {
output.push(line);
}
}
// Mostrar el contenido dentro del encabezado "Highlights" si hay contenido
if (output.length > 0) {
// Mostrar el enlace a la página arriba del contenido de "Highlights"
dv.el('p', page.file.link).addClass("page-link");
// Mostrar el contenido dentro del encabezado "Highlights"
dv.paragraph(output.join('\n')).addClass("omni-pr");
}
}
¿Te gusta este contenido? Suscríbete vía RSS