Dockerizar tu aplicaci贸n React (Vite)
Dockerizar tu aplicaci贸n React (Vite) 馃惓⚛️
Vamos a crear un contenedor Docker para tu app React creada con Vite. Veremos dos escenarios:
Modo desarrollo → con hot-reload (para seguir programando dentro de Docker).
Modo producci贸n → build optimizado con Nginx (para desplegar).
馃搵 Requisitos previos
| Herramienta | Verificar con |
|---|---|
| Docker Desktop | docker --version |
| Docker Compose | docker compose version |
| Tu app React funcionando localmente | npm run dev |
Estructura de partida (asumo que seguiste el tutorial anterior):
pasteles-app/
├── src/
├── public/
├── index.html
├── package.json
├── vite.config.js
└── ...1️⃣ Crear el archivo .dockerignore
En la ra铆z de pasteles-app/, crea .dockerignore:
node_modules
dist
build
.git
.gitignore
.env
.env.local
.vscode
.idea
*.log
npm-debug.log*
.DS_Store
Dockerfile
docker-compose.yml
README.md¿Por qu茅? Sin esto, Docker copiar铆a tu node_modules local (que puede pesar cientos de MB y tener binarios de tu SO) al contenedor, causando conflictos y builds lentos.
2️⃣ Configurar Vite para exponerse fuera del contenedor
Edita vite.config.js:
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
host: '0.0.0.0', // 馃憟 Permite conexiones desde fuera del contenedor
port: 5173,
strictPort: true,
watch: {
usePolling: true, // 馃憟 Necesario en Windows/Mac con Docker Desktop
},
},
});Sin host: '0.0.0.0', Vite solo escucha en localhost dentro del contenedor y no podr谩s acceder desde tu navegador.
馃叞️ MODO DESARROLLO (con hot-reload)
Este es el modo recomendado mientras programas.
3️⃣A Crear Dockerfile.dev
En la ra铆z de pasteles-app/:
# Dockerfile.dev
FROM node:20-alpine
WORKDIR /app
# Copiamos solo los manifiestos primero (mejor cach茅 de capas)
COPY package*.json ./
# Instalamos dependencias
RUN npm install
# Copiamos el resto del c贸digo
COPY . .
# Exponemos el puerto de Vite
EXPOSE 5173
# Comando para desarrollo
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]4️⃣A Crear docker-compose.dev.yml
# docker-compose.dev.yml
services:
react-dev:
build:
context: .
dockerfile: Dockerfile.dev
container_name: pasteles-react-dev
ports:
- "5173:5173"
volumes:
# Montamos el c贸digo para hot-reload
- .:/app
# Volumen an贸nimo para node_modules (evita sobrescribirlo)
- /app/node_modules
environment:
- CHOKIDAR_USEPOLLING=true
- VITE_API_URL=http://localhost:8000/api
stdin_open: true
tty: true
networks:
- pasteles-net
networks:
pasteles-net:
driver: bridge馃挕 El volumen
- /app/node_moduleses truco clave: le dice a Docker que mantenga losnode_modulesdel contenedor (Linux) y no los de tu m谩quina host. Sin esto, ver谩s errores comoCannot find module 'vite'.
5️⃣A Levantar el contenedor en modo desarrollo
# Construir y levantar
docker compose -f docker-compose.dev.yml up --build
# O en segundo plano
docker compose -f docker-compose.dev.yml up -d --buildVer谩s algo como:
pasteles-react-dev | VITE v5.x ready in 300 ms
pasteles-react-dev | ➜ Local: http://localhost:5173/Abre http://localhost:5173 en tu navegador. 馃帀
6️⃣A Comandos 煤tiles (modo dev)
# Ver logs en vivo
docker compose -f docker-compose.dev.yml logs -f
# Detener
docker compose -f docker-compose.dev.yml down
# Entrar a la terminal del contenedor
docker exec -it pasteles-react-dev sh
# Instalar una nueva dependencia (dentro del contenedor)
docker exec -it pasteles-react-dev npm install axios
# Reconstruir desde cero
docker compose -f docker-compose.dev.yml down -v
docker compose -f docker-compose.dev.yml up --build馃叡️ MODO PRODUCCI脫N (con Nginx)
Este es el modo que usar谩s para desplegar. Genera un build est谩tico y lo sirve con Nginx.
3️⃣B Crear Dockerfile (multi-stage)
En la ra铆z de pasteles-app/:
# ---------- ETAPA 1: BUILD ----------
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
# Variable de entorno para el build (apunta al backend de Laravel)
ARG VITE_API_URL=http://localhost:8000/api
ENV VITE_API_URL=$VITE_API_URL
RUN npm run build
# ---------- ETAPA 2: SERVIDOR ----------
FROM nginx:1.27-alpine
# Copiamos la config personalizada de Nginx
COPY nginx.conf /etc/nginx/conf.d/default.conf
# Copiamos el build generado desde la etapa 1
COPY --from=builder /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]4️⃣B Crear nginx.conf
En la ra铆z de pasteles-app/:
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Gzip para mejor performance
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
gzip_min_length 1000;
# Cache agresivo para assets (tienen hash en el nombre)
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2?)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# SPA fallback: cualquier ruta → index.html (para React Router)
location / {
try_files $uri $uri/ /index.html;
}
}馃挕 El
try_files ... /index.htmles clave para SPA. Sin esto, si el usuario recarga en/pasteles/5, Nginx dar铆a 404 porque esa ruta no existe como archivo. React Router maneja eso en el cliente.
5️⃣B Crear docker-compose.yml (producci贸n)
# docker-compose.yml
services:
react-prod:
build:
context: .
dockerfile: Dockerfile
args:
VITE_API_URL: http://localhost:8000/api
container_name: pasteles-react-prod
ports:
- "8080:80"
restart: unless-stopped
networks:
- pasteles-net
networks:
pasteles-net:
driver: bridge6️⃣B Levantar en modo producci贸n
# Construir la imagen
docker build -t pasteles-react:prod \
--build-arg VITE_API_URL=http://localhost:8000/api .
# O con compose
docker compose up --build -dAbre http://localhost:8080 y ver谩s tu app servida por Nginx. 馃殌
7️⃣ ⚠️ Conectar React con Laravel en Docker (CORS)
Como ahora React corre en http://localhost:8080 (prod) o http://localhost:5173 (dev), debes agregar esos or铆genes a CORS en Laravel.
Edita config/cors.php:
'allowed_origins' => [
'http://localhost:5173', // dev
'http://localhost:8080', // prod
],Y limpia la cach茅:
php artisan config:clear8️⃣ (Opcional) Dockerizar tambi茅n Laravel + MySQL
Si quieres levantar todo el stack con un solo comando, aqu铆 va un docker-compose.yml completo en la ra铆z del proyecto padre:
proyecto/
├── laravel-app/ ← tu backend
├── pasteles-app/ ← tu frontend React
└── docker-compose.yml ← orquestadordocker-compose.yml:
services:
db:
image: mysql:8.0
container_name: pasteles-db
restart: unless-stopped
environment:
MYSQL_DATABASE: laravel_db
MYSQL_ROOT_PASSWORD: root
MYSQL_PASSWORD: secret
MYSQL_USER: laravel
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
networks:
- pasteles-net
laravel:
build:
context: ./laravel-app
dockerfile: Dockerfile
container_name: pasteles-laravel
ports:
- "8000:8000"
depends_on:
- db
environment:
DB_CONNECTION: mysql
DB_HOST: db
DB_PORT: 3306
DB_DATABASE: laravel_db
DB_USERNAME: laravel
DB_PASSWORD: secret
networks:
- pasteles-net
react-dev:
build:
context: ./pasteles-app
dockerfile: Dockerfile.dev
container_name: pasteles-react
ports:
- "5173:5173"
volumes:
- ./pasteles-app:/app
- /app/node_modules
environment:
- VITE_API_URL=http://localhost:8000/api
depends_on:
- laravel
networks:
- pasteles-net
networks:
pasteles-net:
driver: bridge
volumes:
db_data:Con esto:
docker compose up -d --buildY tendr谩s los 3 servicios corriendo:
| Servicio | URL |
|---|---|
| React | http://localhost:5173 |
| Laravel API | http://localhost:8000/api/pasteles |
| MySQL | localhost:3306 |
馃搧 Estructura final (solo React)
pasteles-app/
├── src/
├── public/
├── Dockerfile ← Producci贸n (Nginx)
├── Dockerfile.dev ← Desarrollo (Vite)
├── docker-compose.yml ← Producci贸n
├── docker-compose.dev.yml ← Desarrollo
├── nginx.conf ← Config Nginx
├── .dockerignore ← Excluir archivos
├── package.json
├── vite.config.js
└── index.html馃悰 Soluci贸n de problemas comunes
| Error | Causa | Soluci贸n |
|---|---|---|
Cannot find module 'vite' | Volumen sobrescribe node_modules | Agregar - /app/node_modules al volumen |
ERR_CONNECTION_REFUSED desde el navegador | Vite no escucha en 0.0.0.0 | Agregar host: '0.0.0.0' en vite.config.js |
| Hot-reload no funciona (Windows/Mac) | File watching no detecta cambios | usePolling: true en vite.config.js |
CORS policy blocked | Origen no permitido en Laravel | Agregar http://localhost:5173 en config/cors.php |
Build falla con ENOSPC | Docker sin espacio | docker system prune -a |
Nginx da 404 al recargar en /ruta | SPA fallback faltante | Ya lo agregamos en nginx.conf |
port is already allocated | Puerto ocupado | Cambia el puerto o mata el proceso |
馃Ч Comandos 煤tiles de Docker
# Ver contenedores activos
docker ps
# Ver todos (incluidos detenidos)
docker ps -a
# Ver im谩genes
docker images
# Ver uso de recursos
docker stats
# Limpiar todo (⚠️ borra im谩genes y vol煤menes no usados)
docker system prune -a --volumes
# Ver logs de un contenedor espec铆fico
docker logs -f pasteles-react-dev✅ Resumen de comandos
Desarrollo
docker compose -f docker-compose.dev.yml up --build
# → http://localhost:5173Producci贸n
docker compose up --build -d
# → http://localhost:8080Detener
docker compose -f docker-compose.dev.yml down # dev
docker compose down # prod馃幆 ¿Cu谩ndo usar cada modo?
| Escenario | Modo | Archivo |
|---|---|---|
| Estoy programando la app | Dev | Dockerfile.dev + docker-compose.dev.yml |
| Quiero mostrarla al cliente | Prod | Dockerfile + docker-compose.yml |
| Voy a desplegar en un servidor | Prod | Igual, pero cambia VITE_API_URL al dominio real |
Con esto ya tienes tu app React totalmente dockerizada
Comentarios
Publicar un comentario