أساسيات React.js
نشر تطبيقات React
عملية البناء للإنتاج
قبل نشر تطبيق 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+