مقدمة إلى Docker و TypeScript: لماذا نحتاج إلى الحاويات
تطوير الويب الحديث لا يمكن تصوره بدون أدوات تضمن توحيد البيئة. أصبح Docker المعيار الفعلي لتغليف التطبيقات وتسليمها وتشغيلها. بالاقتران مع TypeScript — وهي لغة مكتوبة بشدة تُترجم إلى JavaScript — تمنح الحاويات أداة قوية لإنشاء خدمات قابلة للتوسع وموثوقة.
لماذا نضع تطبيق TypeScript في حاوية؟ أولاً، يحل هذا مشكلة "يعمل على جهازي". ثانيًا، يبسط النشر في بيئة الإنتاج و CI/CD. ثالثًا، يسمح بعزل التبعيات وإصدارات Node.js. في هذه المقالة، سنشرح كيفية إنشاء صورة Docker لتطبيق TypeScript، وإعداد build متعدد المراحل، واستخدام docker-compose للتطوير المحلي.
أساسيات Docker لمطور TypeScript
قبل كتابة الكود، دعنا نذكر المفاهيم الأساسية لـ Docker: image (صورة) — قالب لإنشاء حاوية؛ container (حاوية) — مثيل قيد التشغيل من الصورة؛ Dockerfile — تعليمات بناء الصورة.
لتطبيق TypeScript على Node.js، سنحتاج إلى:
- بيئة تشغيل Node.js (عادةً صورة
node:18-alpineأوnode:20-alpineللحجم الأدنى) - تثبيت التبعيات (
npm installأوyarn install) - ترجمة TypeScript إلى JavaScript (
tsc) - تشغيل التطبيق المترجم
لنلقِ نظرة على مثال بسيط لتطبيق TypeScript (ملف 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}`);});وملف tsconfig.json:
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "outDir": "./dist", "rootDir": "./src", "strict": true, "esModuleInterop": true }, "include": ["src"], "exclude": ["node_modules", "dist"]}الآن سننشئ Dockerfile لهذا التطبيق.
إنشاء Dockerfile لتطبيق TypeScript
قد يبدو Dockerfile الأساسي كالتالي:
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"]هنا يتم استخدام multi-stage build (بناء متعدد المراحل). المرحلة الأولى (builder) تجمع TypeScript إلى JavaScript، والثانية (runner) تحتوي فقط على الكود المترجم وتبعيات وقت التشغيل. هذا يقلل حجم الصورة النهائية — لا يتم تضمين ملفات TypeScript المصدرية وتبعيات التطوير فيها.
هام: ننفذ npm ci (تثبيت نظيف) بدلاً من npm install من أجل قابلية التكرار والسرعة.
تحسين Dockerfile: تخزين الطبقات مؤقتًا
يقوم Docker بتخزين كل طبقة (تعليمة) مؤقتًا. لتسريع البناء، انسخ الملفات التي نادرًا ما تتغير أولاً. على سبيل المثال، يتم نسخ package.json و package-lock.json قبل جميع الملفات المصدرية، لذلك لا تؤدي التغييرات في الكود إلى إعادة تثبيت التبعيات.
بالإضافة إلى ذلك، يمكن إضافة ملف .dockerignore:
node_modulesdist.git*.md.gitignore.envهذا يمنع دخول الملفات غير الضرورية إلى سياق البناء.
docker-compose للتطوير المحلي
لتسهيل التطوير المحلي، استخدم ملف docker-compose.yml. يسمح بتشغيل التطبيق مع إعادة التحميل التلقائي (باستخدام nodemon أو