Capítulo 20 — DevOps para frontend¶
Introducción¶
DevOps es la cultura y el conjunto de prácticas que unen desarrollo y operaciones. En el mundo frontend, significa:
- Automatizar builds, tests y despliegues.
- Monitorizar el rendimiento real de la aplicación.
- Detectar errores en producción antes de que los usuarios se quejen.
- Gestionar versiones y entornos de forma reproducible.
Este capítulo te da las herramientas para llevar tu código desde tu máquina hasta producción con confianza.
CI/CD: la base¶
CI (Continuous Integration): cada push dispara tests y validaciones. CD (Continuous Delivery/Deployment): cada cambio validado se despliega automáticamente.
GitHub Actions¶
El estándar de facto. Los workflows se definen en .github/workflows/*.yml.
Pipeline completo¶
name: CI/CD
on:
push:
branches: [main]
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Instalar dependencias
run: npm ci
- name: Lint
run: npm run lint
- name: Tests
run: npm run test:run
- name: Build
run: npm run build
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- name: Desplegar
run: npx vercel deploy --prod --token=${{ secrets.VERCEL_TOKEN }}
npm ci en lugar de npm install
En CI, usa npm ci. Es más rápido, reproducible y falla si package-lock.json no está sincronizado.
Validaciones automáticas¶
Linting con ESLint¶
npm install -D eslint
npx eslint --init
{
"scripts": {
"lint": "eslint src --max-warnings 0"
}
}
Formateo con Prettier¶
npm install -D prettier
.prettierrc:
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"printWidth": 80
}
Añade scripts:
{
"scripts": {
"format": "prettier --write .",
"format:check": "prettier --check ."
}
}
Husky + lint-staged¶
Ejecuta lint y formato antes de cada commit:
npm install -D husky lint-staged
npx husky init
package.json:
{
"lint-staged": {
"*.{js,ts,jsx,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["prettier --write"],
"*.md": ["prettier --write"]
}
}
.husky/pre-commit:
npx lint-staged
Versionado semántico¶
SemVer: MAYOR.MENOR.PARCHE
- MAYOR: cambios incompatibles.
- MENOR: nuevas funcionalidades compatibles.
- PARCHE: corrección de errores.
Ejemplo: 1.4.2 → 2.0.0 (breaking change).
Gestionado con Changesets:
npm install -D @changesets/cli
npx changeset init
npx changeset # describe el cambio
npx changeset version
Monitorización y errores¶
Sentry¶
Captura errores en producción con contexto (navegador, usuario, stacktrace).
npm install @sentry/react
import * as Sentry from '@sentry/react';
Sentry.init({
dsn: 'https://...@sentry.io/...',
environment: import.meta.env.MODE,
tracesSampleRate: 0.1,
});
Con Sentry ves:
- Errores agrupados por tipo.
- Cuántos usuarios afectados.
- Stack trace con source maps.
- Releases y regresiones.
Web Vitals en producción¶
Envía las métricas reales de tus usuarios:
npm install web-vitals
import { onCLS, onINP, onLCP } from 'web-vitals';
function enviar({ name, value, id }) {
navigator.sendBeacon('/api/vitals', JSON.stringify({ name, value, id }));
}
onCLS(enviar);
onINP(enviar);
onLCP(enviar);
Analiza en tu backend o con servicios como Vercel Analytics o SpeedCurve.
Logs estructurados¶
En backend, usa pino:
npm install pino
import pino from 'pino';
const logger = pino({ level: 'info' });
logger.info({ userId: 42 }, 'Usuario logueado');
logger.error({ err }, 'Fallo al guardar');
En frontend, considera herramientas como LogRocket o Datadog RUM para sesiones grabadas.
Feature flags¶
Permiten activar/desactivar funcionalidades sin desplegar. Útil para:
- Lanzamientos graduales.
- Pruebas A/B.
- Kill switches.
const flags = {
nuevoDiseno: false,
};
if (flags.nuevoDiseno) {
// nuevo layout
} else {
// layout clásico
}
En serio, con LaunchDarkly, Unleash o PostHog.
Entornos¶
Separa al menos tres entornos:
| Entorno | URL | Cuándo |
|---|---|---|
| Development | localhost |
Desarrollo local |
| Staging | staging.miapp.com |
Pruebas antes de producción |
| Production | miapp.com |
Usuarios reales |
Cada uno con sus propias variables de entorno, base de datos y claves.
Docker para frontend¶
Aunque el frontend no lo necesite para desarrollo, Docker ayuda a garantizar reproducibilidad.
Dockerfile para SPA¶
# Build
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Serve
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
nginx.conf¶
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
# SPA fallback
location / {
try_files $uri $uri/ /index.html;
}
# Cache largo para assets con hash
location ~* \.(js|css|woff2|png|jpg|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Docker Compose¶
services:
web:
build: .
ports:
- "8080:80"
api:
build: ./api
environment:
DATABASE_URL: postgres://user:pass@db:5432/app
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: pass
volumes:
- pgdata:/var/lib/postgresql/data
volumes:
pgdata:
Secretos y seguridad¶
- Nunca metas secretos en el repositorio.
- Usa GitHub Secrets para CI/CD.
- En Vercel/Netlify: variables en su panel.
- Rota las claves periódicamente.
- Escanea dependencias:
npm audit
npm audit fix
Añade Dependabot para PRs automáticos de actualización:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
Rollbacks¶
Un buen despliegue permite volver atrás en segundos.
- Vercel/Netlify: historial de deploys con "Promote to production".
- Docker + Kubernetes:
kubectl rollout undo. - S3 + CloudFront: versionar el bucket.
Siempre ten un plan B. Si el despliegue rompe producción, debes poder revertir en menos de 60 segundos.
Postmortems¶
Cuando algo falle en producción, escribe un postmortem sin culpar a nadie:
- Qué pasó.
- Impacto.
- Timeline.
- Causa raíz.
- Qué se hizo bien.
- Acciones para evitar que se repita.
Es la mejor forma de aprender de los errores.
Buenas prácticas¶
- CI en cada PR. Nunca mergees sin tests en verde.
- Deploys pequeños y frecuentes. Mejor que uno grande cada mes.
- Feature flags para cambios de riesgo.
- Monitoriza en producción. Los usuarios son tu mejor test.
- Alertas útiles. Solo lo que requiere acción inmediata.
- Documenta el proceso. Onboarding rápido.
- Rollback fácil. Automatizado.
- Automatiza todo lo repetitivo.
- Backups regulares de la base de datos.
- Ambiente staging que refleje producción.
Ejercicios¶
- Configura un workflow de GitHub Actions con lint + test + build.
- Añade Husky + lint-staged a un proyecto tuyo.
- Integra Sentry en una app y captura un error forzado.
- Añade
web-vitalsy envía las métricas a tu backend. - Crea un Dockerfile multi-stage para una SPA con Nginx.
- Configura Dependabot para actualizar dependencias semanalmente.
- Escribe un postmortem de un bug real que hayas tenido.
- Despliega la misma app en staging y producción con diferentes variables.