Docker y TypeScript: contenedorización de aplicaciones desde cero

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Introducción: ¿por qué contenerizar aplicaciones TypeScript?



El desarrollo de software moderno es impensable sin la contenerización. Docker se ha convertido en el estándar de facto para empaquetar, distribuir y ejecutar aplicaciones en entornos aislados. En combinación con TypeScript —un superconjunto de JavaScript con tipado estricto— Docker proporciona previsibilidad, portabilidad y simplifica los procesos de CI/CD.



En este artículo analizaremos cómo contenerizar correctamente una aplicación TypeScript: desde un Dockerfile básico hasta una compilación lista para producción utilizando docker-compose y compilación multi-etapa. Aprenderá cómo evitar errores típicos, reducir el tamaño de la imagen y acelerar el despliegue.



Fundamentos: TypeScript y Node.js en Docker



TypeScript es un lenguaje que se compila a JavaScript. Esto significa que para ejecutar una aplicación TypeScript en un contenedor, primero debemos compilar el código fuente y luego ejecutar el JavaScript resultante con Node.js. Docker es ideal para automatizar este proceso.



Creación de una aplicación TypeScript simple



Para empezar, crearemos una aplicación mínima en TypeScript. Estructura del proyecto:



my-ts-app/├── src/│   └── index.ts├── package.json├── tsconfig.json└── Dockerfile


src/index.ts:



import express, { Request, Response } from 'express';

const app = express();const PORT = process.env.PORT || 3000;

app.get('/', (req: Request, res: Response) => { res.json({ message: 'Hello from TypeScript + Docker!' });});

app.listen(PORT, () => { console.log(`Server is running on port ${PORT}`);});


package.json:



{  "name": "my-ts-app",  "version": "1.0.0",  "scripts": {    "build": "tsc",    "start": "node dist/index.js",    "dev": "ts-node src/index.ts"  },  "dependencies": {    "express": "^4.18.2"  },  "devDependencies": {    "@types/express": "^4.17.21",    "@types/node": "^20.11.0",    "typescript": "^5.3.3",    "ts-node": "^10.9.2"  }}


tsconfig.json:



{  "compilerOptions": {    "target": "ES2020",    "module": "commonjs",    "outDir": "./dist",    "rootDir": "./src",    "strict": true,    "esModuleInterop": true,    "skipLibCheck": true  },  "include": ["src/**/*"]}


Dockerfile básico



La primera versión, la más simple del Dockerfile:



FROM node:20-alpine

WORKDIR /app

COPY package*.json ./RUN npm install

COPY . .

RUN npm run build

EXPOSE 3000

CMD ["npm", "start"]


Este Dockerfile copia todo el proyecto, instala las dependencias, compila TypeScript y ejecuta la aplicación. Sin embargo, este enfoque tiene desventajas: el tamaño de la imagen es grande y el almacenamiento en caché de las capas no es eficiente.



Optimización: compilación multi-etapa y reducción de tamaño



Para entornos de producción, se recomienda utilizar la compilación multi-etapa (multi-stage build). Esto permite separar las etapas de compilación y ejecución, dejando solo los archivos necesarios en la imagen final.



Dockerfile de producción con compilación multi-etapa



# Stage 1: BuildFROM node:20-alpine AS builder

WORKDIR /app

COPY package*.json ./RUN npm ci --only=production

COPY . .RUN npm run build

# Stage 2: ProductionFROM node:20-alpine

WORKDIR /app

COPY --from=builder /app/dist ./distCOPY --from=builder /app/node_modules ./node_modulesCOPY --from=builder /app/package.json ./

EXPOSE 3000

USER node

CMD ["node", "dist/index.js"]


Ventajas de este enfoque:

  • Menor tamaño de imagen — la capa final contiene solo el código compilado y las dependencias de producción.
  • Seguridad — el código fuente de TypeScript y las dependencias de desarrollo no permanecen en el contenedor.

Blogs

Book Recommendations