أساسيات React.js

نشر تطبيقات React

15 دقيقة الدرس 37 من 40

عملية البناء للإنتاج

قبل نشر تطبيق React الخاص بك، تحتاج إلى إنشاء بناء إنتاج محسّن. تقوم هذه العملية بتصغير الكود وإزالة تحذيرات التطوير وتحسين الأداء.

إنشاء بناء الإنتاج

# لـ Create React App npm run build # لـ Vite npm run build # لـ Next.js npm run build npm start # بدء خادم الإنتاج # مخرجات البناء build/ ├── static/ │ ├── css/ │ │ └── main.abc123.css │ ├── js/ │ │ ├── main.xyz789.js │ │ └── vendor.def456.js │ └── media/ ├── index.html └── asset-manifest.json
تحسينات البناء:
  • التصغير: يتم ضغط الكود وإزالة المسافات البيضاء
  • Tree Shaking: يتم إزالة الكود غير المستخدم
  • تقسيم الكود: يتم تقسيم JS إلى أجزاء أصغر
  • هاش الأصول: الملفات تحصل على هاش فريد لكسر الكاش
  • متغيرات البيئة: يتم حقن قيم الإنتاج

متغيرات البيئة

البيئات المختلفة تحتاج إلى إعدادات مختلفة. تطبيقات React تتعامل مع متغيرات البيئة بشكل آمن:

# .env.development REACT_APP_API_URL=http://localhost:3000/api REACT_APP_ENVIRONMENT=development REACT_APP_ANALYTICS_ID= # .env.production REACT_APP_API_URL=https://api.myapp.com REACT_APP_ENVIRONMENT=production REACT_APP_ANALYTICS_ID=GA-XXXXX-Y # الوصول في الكود const apiUrl = process.env.REACT_APP_API_URL; const isDev = process.env.NODE_ENV === 'development'; if (process.env.REACT_APP_ANALYTICS_ID) { initAnalytics(process.env.REACT_APP_ANALYTICS_ID); }
تحذير أمني: لا تقم أبداً بإرسال مفاتيح حساسة إلى التحكم في الإصدار!
  • أنشئ .env.local للأسرار (يتم تجاهله تلقائياً بواسطة CRA)
  • استخدم بادئة REACT_APP_ فقط للمتغيرات العامة
  • احفظ مفاتيح API والرموز على الخلفية، وليس في تطبيق React
  • استخدم متغيرات بيئة CI/CD لأسرار النشر

النشر على Vercel

Vercel توفر أسهل تجربة نشر لتطبيقات React، خاصة Next.js:

# تثبيت Vercel CLI npm install -g vercel # تسجيل الدخول vercel login # النشر من دليل المشروع vercel # النشر إلى الإنتاج vercel --prod # إعدادات vercel.json { "buildCommand": "npm run build", "outputDirectory": "build", "framework": "create-react-app", "env": { "REACT_APP_API_URL": "@api-url" }, "regions": ["iad1"], "github": { "enabled": true, "autoAlias": true } }
ميزات Vercel:
  • النشر التلقائي: ادفع إلى Git، نشر تلقائي
  • روابط المعاينة: كل PR يحصل على رابط معاينة فريد
  • شبكة Edge: CDN مع أكثر من 100 موقع عالمي
  • صفر إعداد: يكتشف الإطار تلقائياً
  • وظائف Serverless: أضف مسارات API بسهولة

النشر على Netlify

Netlify هي منصة ممتازة أخرى للمواقع الثابتة وتطبيقات React:

# تثبيت Netlify CLI npm install -g netlify-cli # تسجيل الدخول netlify login # تهيئة المشروع netlify init # النشر netlify deploy # النشر إلى الإنتاج netlify deploy --prod # إعدادات netlify.toml [build] command = "npm run build" publish = "build" [build.environment] NODE_VERSION = "18" REACT_APP_API_URL = "https://api.myapp.com" [[redirects]] from = "/*" to = "/index.html" status = 200 [[headers]] for = "/static/*" [headers.values] Cache-Control = "public, max-age=31536000, immutable"
إصلاح توجيه SPA: قاعدة إعادة التوجيه /* → /index.html ضرورية للتوجيه من جانب العميل! بدونها، تحديث /about يعيد 404. هذا يخبر الخادم أن يقدم دائماً index.html، مما يسمح لـ React Router بالتعامل مع التنقل.

النشر مع Docker

حاويات Docker توفر بيئات متسقة عبر التطوير والإنتاج:

# Dockerfile FROM node:18-alpine AS build WORKDIR /app # نسخ ملفات الحزمة COPY package*.json ./ RUN npm ci # نسخ المصدر والبناء COPY . . RUN npm run build # مرحلة الإنتاج مع nginx FROM nginx:alpine # نسخ ملفات البناء COPY --from=build /app/build /usr/share/nginx/html # نسخ إعدادات nginx COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
# nginx.conf server { listen 80; server_name _; root /usr/share/nginx/html; index index.html; # تفعيل ضغط gzip gzip on; gzip_types text/css application/javascript application/json image/svg+xml; gzip_min_length 1000; # التخزين المؤقت للأصول الثابتة location /static/ { expires 1y; add_header Cache-Control "public, immutable"; } # احتياطي SPA location / { try_files $uri $uri/ /index.html; } }
# بناء وتشغيل حاوية Docker docker build -t my-react-app . docker run -p 80:80 my-react-app # docker-compose.yml version: '3.8' services: web: build: . ports: - "80:80" environment: - NODE_ENV=production restart: unless-stopped

خط أنابيب CI/CD مع GitHub Actions

أتمتة الاختبار والنشر مع التكامل المستمر:

# .github/workflows/deploy.yml name: Deploy to Production on: push: branches: [main] jobs: build-and-deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run tests run: npm test -- --coverage --watchAll=false - name: Build run: npm run build env: REACT_APP_API_URL: ${{ secrets.API_URL }} REACT_APP_ANALYTICS_ID: ${{ secrets.ANALYTICS_ID }} - name: Deploy to Vercel uses: amondnet/vercel-action@v20 with: vercel-token: ${{ secrets.VERCEL_TOKEN }} vercel-org-id: ${{ secrets.ORG_ID }} vercel-project-id: ${{ secrets.PROJECT_ID }} vercel-args: '--prod'
أفضل ممارسات CI/CD:
  • تشغيل الاختبارات: منع نشر الكود المعطوب
  • فحص الكود: فرض معايير جودة الكود
  • فحص الأمان: التحقق من الثغرات (npm audit)
  • نشر المعاينة: نشر PRs إلى روابط staging
  • خطة التراجع: الحفاظ على القدرة على العودة إلى النسخة السابقة

تحسين الأداء للإنتاج

تحسينات إضافية لتنفيذها قبل النشر:

// 1. تقسيم الكود مع React.lazy import React, { lazy, Suspense } from 'react'; const Dashboard = lazy(() => import('./Dashboard')); const Profile = lazy(() => import('./Profile')); function App() { return ( <Suspense fallback={<LoadingSpinner />}> <Routes> <Route path="/dashboard" element={<Dashboard />} /> <Route path="/profile" element={<Profile />} /> </Routes> </Suspense> ); } // 2. تحسين الصور import { LazyLoadImage } from 'react-lazy-load-image-component'; function ProductImage({ src, alt }) { return ( <LazyLoadImage src={src} alt={alt} effect="blur" width={400} height={300} /> ); } // 3. Service Worker للدعم دون اتصال if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker .register('/service-worker.js') .then(registration => { console.log('SW مسجل:', registration); }) .catch(error => { console.log('فشل تسجيل SW:', error); }); }); }

المراقبة والتحليلات

// إعداد تتبع الأخطاء مع Sentry import * as Sentry from "@sentry/react"; Sentry.init({ dsn: process.env.REACT_APP_SENTRY_DSN, environment: process.env.REACT_APP_ENVIRONMENT, tracesSampleRate: 1.0, }); // إعداد Google Analytics import ReactGA from 'react-ga4'; ReactGA.initialize(process.env.REACT_APP_GA_ID); function App() { const location = useLocation(); useEffect(() => { ReactGA.send({ hitType: "pageview", page: location.pathname }); }, [location]); return <Routes>...</Routes>; } // مراقبة الأداء import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'; function sendToAnalytics({ name, value, id }) { ReactGA.event({ category: 'Web Vitals', action: name, value: Math.round(value), label: id, }); } getCLS(sendToAnalytics); getFID(sendToAnalytics); getFCP(sendToAnalytics); getLCP(sendToAnalytics); getTTFB(sendToAnalytics);
تمرين 1: انشر تطبيق React الخاص بك على Vercel:
  • أنشئ بناء إنتاج محلياً واختبره
  • قم بإعداد متغيرات البيئة للبيئات المختلفة
  • اربط مستودع GitHub الخاص بك بـ Vercel
  • قم بتكوين النشر التلقائي عند الدفع إلى main
  • قم بإعداد نشر المعاينة لطلبات السحب
تمرين 2: أنشئ خط أنابيب CI/CD كامل:
  • قم بإعداد سير عمل GitHub Actions
  • أضف خطوات لـ: التثبيت، الفحص، الاختبار، البناء
  • قم بتكوين النشر إلى منصة الاستضافة الخاصة بك
  • أضف شارات الحالة إلى README الخاص بك
  • اختبر خط الأنابيب عن طريق دفع التغييرات
تمرين 3: حسّن بناء الإنتاج الخاص بك:
  • نفّذ تقسيم الكود لـ 3 مسارات على الأقل
  • أضف التحميل الكسول للصور
  • قم بإعداد مراقبة الأداء (Web Vitals)
  • قم بتكوين رؤوس التخزين المؤقت للأصول الثابتة
  • قم بتشغيل تدقيق Lighthouse واحصل على درجات 90+