Introduction à Docker et TypeScript : pourquoi la conteneurisation est nécessaire
Le développement web moderne est impensable sans des outils garantissant l'uniformité de l'environnement. Docker est devenu le standard de facto pour empaqueter, livrer et exécuter des applications. Combiné à TypeScript — un langage fortement typé compilé en JavaScript — la conteneurisation offre un outil puissant pour créer des services évolutifs et fiables.
Pourquoi conteneuriser une application TypeScript ? Premièrement, cela résout le problème « ça marche sur ma machine ». Deuxièmement, cela simplifie le déploiement en production et l'intégration continue/déploiement continu (CI/CD). Troisièmement, cela permet d'isoler les dépendances et les versions de Node.js. Dans cet article, nous allons voir comment créer une image Docker pour une application TypeScript, configurer une construction multi-stage et utiliser docker-compose pour le développement local.
Les bases de Docker pour un développeur TypeScript
Avant d'écrire du code, rappelons les concepts de base de Docker : une image (image) est un modèle pour créer un conteneur ; un conteneur (container) est une instance en cours d'exécution d'une image ; un Dockerfile est une instruction pour construire une image.
Pour une application TypeScript sur Node.js, nous aurons besoin de :
- L'environnement d'exécution Node.js (généralement l'image
node:18-alpineounode:20-alpinepour une taille minimale) - L'installation des dépendances (
npm installouyarn install) - La compilation de TypeScript en JavaScript (
tsc) - L'exécution de l'application compilée
Considérons un exemple simple d'application TypeScript (fichier src/index.ts) :
import express from 'express';
const app = express();const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => { res.send('Hello from TypeScript + Docker!');});
app.listen(PORT, () => { console.log(`Server running on port ${PORT}`);});Et le fichier tsconfig.json :
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }, "include": ["src"], "exclude": ["node_modules", "dist"]}Créons maintenant un Dockerfile pour cette application.
Création d'un Dockerfile pour une application TypeScript
Un Dockerfile de base pourrait ressembler à ceci :
FROM node:18-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build
FROM node:18-alpine AS runnerWORKDIR /appCOPY --from=builder /app/dist ./distCOPY --from=builder /app/package*.json ./COPY --from=builder /app/node_modules ./node_modulesEXPOSE 3000CMD ["node", "dist/index.js"]Ici, on utilise une construction multi-stage (multi-stage build). La première étape (builder) compile TypeScript en JavaScript, la seconde (runner) contient uniquement le code compilé et les dépendances d'exécution. Cela réduit la taille de l'image finale — les sources TypeScript et les dépendances de développement ne sont pas incluses.
Important : nous exécutons npm ci (installation propre) au lieu de npm install pour la reproductibilité et la rapidité.
Optimisation du Dockerfile : mise en cache des couches
Docker met en cache chaque couche (instruction). Pour accélérer la construction, copiez les fichiers qui changent rarement en premier. Par exemple, package.json et package-lock.json sont copiés avant tous les fichiers sources, donc les modifications du code n'entraînent pas une réinstallation des dépendances.
De plus, vous pouvez ajouter un fichier .dockerignore :
node_modulesdist.git*.md.gitignore.envCela empêche les fichiers inutiles d'entrer dans le contexte de construction.
docker-compose pour le développement local
Pour faciliter le développement local, utilisez docker-compose.yml. Il permet d'exécuter l'application avec un rechargement automatique (en utilisant nodemon ou