مقدمة: لماذا نستخدم الحاويات لتطبيقات TypeScript؟
تطوير البرمجيات الحديثة لا يمكن تصوره بدون استخدام الحاويات. أصبح Docker المعيار الفعلي لتغليف التطبيقات وتسليمها وتشغيلها في بيئات معزولة. وبالاقتران مع TypeScript — وهي مجموعة شاملة من JavaScript ذات كتابة صارمة — يوفر Docker قابلية التنبؤ وقابلية النقل ويبسط عمليات CI/CD.
في هذه المقالة، سنشرح كيفية وضع تطبيق TypeScript في حاوية بشكل صحيح: بدءًا من Dockerfile الأساسي وصولاً إلى بناء جاهز للإنتاج باستخدام docker-compose والبناء متعدد المراحل. ستتعلم كيفية تجنب الأخطاء الشائعة، وتقليل حجم الصورة، وتسريع النشر.
الأساسيات: TypeScript و Node.js في Docker
TypeScript هي لغة يتم تجميعها إلى JavaScript. هذا يعني أنه لتشغيل تطبيق TypeScript في حاوية، نحتاج أولاً إلى تجميع الكود المصدري، ثم تنفيذ JavaScript الناتج باستخدام Node.js. يعتبر Docker مثاليًا لأتمتة هذه العملية.
إنشاء تطبيق TypeScript بسيط
للبدء، لننشئ تطبيقًا بسيطًا باستخدام TypeScript. هيكل المشروع:
my-ts-app/├── src/│ └── index.ts├── package.json├── tsconfig.json└── Dockerfilesrc/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 أساسي
الخيار الأول والأبسط لـ Dockerfile:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]يقوم هذا Dockerfile بنسخ المشروع بأكمله، وتثبيت التبعيات، وتجميع TypeScript، وتشغيل التطبيق. ومع ذلك، فإن لهذا النهج عيوبًا: حجم الصورة كبير، والتخزين المؤقت للطبقات غير فعال.
التحسين: البناء متعدد المراحل وتقليل الحجم
لبيئة الإنتاج، يُوصى باستخدام البناء متعدد المراحل (multi-stage build). يتيح ذلك فصل مراحل البناء والتنفيذ، مع ترك الملفات الضرورية فقط في الصورة النهائية.
Dockerfile للإنتاج مع البناء متعدد المراحل
# 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"]مزايا هذا النهج:
- حجم صورة أصغر — تحتوي الطبقة النهائية فقط على الكود المترجم وتبعيات الإنتاج.
- الأمان — لا يبقى كود TypeScript المصدر في الحاوية، وتبعيات dev