Next.js: CI/CD مع GitHub Actions

آخر تحديث: 2026-08-26

CI/CD يشبه "الطيار الآلي" لفرق التطوير — كل commit يمر تلقائيا عبر بوابة الجودة، ولا يصل إلى بيئة الإنتاج إلا الكود الذي يجتاز الاختبارات.

1. ما ستتعلمه



2. قصة حقيقية لمدير تقني

(1) نقطة الألم: النشر اليدوي — ما زلت تحدق في الطرفية في الثالثة صباحا

بوب هو المدير التقني لفريق TaskFlow، المكون من خمسة أعضاء يديرون منصة SaaS تخدم أكثر من 10,000 مستخدم. عملية الإصدار كل يوم جمعة تسير هكذا:

"أليس تدمج PR ← تبلغ بوب ← بوب يشغل الاختبارات محليا ← ينقر يدويا على vercel deploy --prod بعد نجاح الاختبارات ← يحدق في الطرفية لمدة 10 دقائق ← يؤكد نجاح النشر ← يرسل رسالة للفريق"

الأسبوع الماضي، نشر بوب نسخة قديمة بالخطأ لأنه نسي سحب آخر كود قبل npm run build. بعد خمس دقائق، لم يتمكن المستخدمون من تسجيل الدخول، واستغرق الأمر 15 دقيقة أخرى للتراجع عن التغييرات. تلقى قسم خدمة العملاء أكثر من 100 شكوى.

نقاط الألم التأثير
النشر اليدوي معدل خطأ بشري مرتفع (30% من الإصدارات بها مشاكل)
لا يوجد اختبار آلي للتحكم في الوصول الكود المعيب قد يصل إلى الإنتاج
عدم تطابق البيئة يعمل محليا، لكنه يرمي خطأ في الإنتاج
لا توجد معاينة PR لا يمكنك رؤية النتائج قبل الدمج

(2) حل GitHub Actions

صمم بوب ثلاثة خطوط تجميع آلية:

YAML
# كل مرة PR ← فحص تلقائي + اختبار + بناء
# الدمج في main ← بناء تلقائي + نشر إلى Vercel
# كل يوم عند الفجر ← بناء تلقائي لصورة Docker

(3) النتائج

البعد النشر اليدوي أتمتة CI/CD
وقت النشر 30 دقيقة 8 دقائق
الخطأ البشري 30% < 1%
كفاءة مراجعة PR الكود فقط الكود + رابط المعاينة
تكرار النشر مرة أسبوعيا 5 مرات يوميا


3. أساسيات GitHub Actions

Actions هي منصة CI/CD المدمجة في GitHub تستخدم ملفات YAML لتعريف سير العمل.

100%
graph LR
    A[git push] --> B[GitHub Actions]
    B --> C[المشغلات Events]
    C --> D[المهام Jobs متوازية/متسلسلة]
    D --> E[الخطوات Steps]
    E --> F[مكونات سوق Actions]
    
    style B fill:#cce5ff
    style D fill:#d4edda
المفهوم الوصف مثال
Workflow ملف YAML واحد = عملية أتمتة واحدة .github/workflows/test.yml
Event الحدث الذي يشغل سير العمل push، pull_request، schedule
Job مجموعة من الخطوات (قد تكون متوازية أو تابعة) linttestdeploy
Step أمر واحد أو Action npm run lint، actions/checkout
Runner بيئة التنفيذ ubuntu-latest، windows-latest

(1) هيكل ملف Workflow

YAML
# .github/workflows/ci.yml
name: CI Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  NODE_VERSION: '20'
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
      - run: npm ci
      - run: npm run lint

  test:
    needs: [lint]
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: ['18', '20', '22']
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test
      - run: npm run test:coverage
      - uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  build:
    needs: [test]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
      - run: npm ci
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .next/


4. test.yml: اختبار المصفوفة المتوازية

100%
graph TB
    A[Git Push / PR] --> B[lint]
    B --> C[test 18.x]
    B --> D[test 20.x]
    B --> E[test 22.x]
    C --> F[build]
    D --> F
    E --> F
    F --> G[رفع مخرجات البناء]
    
    style A fill:#cce5ff
    style C fill:#d4edda
    style D fill:#d4edda
    style E fill:#d4edda

(1) ملف test.yml الكامل

YAML
# .github/workflows/test.yml
name: Test Suite

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    name: Lint Check
    runs-on: ubuntu-latest
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
          
      - name: TypeScript type check
        run: npx tsc --noEmit
        
      - name: ESLint check
        run: npm run lint
        
      - name: Prettier check
        run: npx prettier --check "src/**/*.{ts,tsx}"

  unit-and-integration:
    name: Unit & Integration Tests
    needs: [lint]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    
    strategy:
      matrix:
        node-version: ['18', '20', '22']
      fail-fast: false
    
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
          
      - name: Generate Prisma client
        run: npx prisma generate
          
      - name: Run database migrations
        run: npx prisma migrate deploy
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Run unit tests
        run: npm run test
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Run integration tests
        run: npm run test:integration
        env:
          DATABASE_URL: postgresql://test:test@localhost:5432/testdb
          
      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          flags: unittests
          name: codecov-node-${{ matrix.node-version }}

  e2e:
    name: E2E Tests
    needs: [lint]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
          
      - name: Install dependencies
        run: npm ci
          
      - name: Install Playwright browsers
        run: npx playwright install --with-deps chromium
        
      - name: Run E2E tests
        run: npx playwright test --project=chromium
        env:
          TEST_DATABASE_URL: ${{ secrets.TEST_DATABASE_URL }}
          
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: playwright-report
          path: playwright-report/
          retention-days: 7

  build:
    name: Build Check
    needs: [unit-and-integration]
    runs-on: ubuntu-latest
    timeout-minutes: 10
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run build
      
      - uses: actions/upload-artifact@v4
        with:
          name: next-build
          path: .next/
          retention-days: 1

▶ مثال: نتائج اختبار المصفوفة المتوازية

TEXT 📖 للعرض فقط
# مخرجات وحدة تحكم GitHub Actions
Job: unit-and-integration (node-version: 18.x)  ✓ 3m 12s
Job: unit-and-integration (node-version: 20.x)  ✓ 2m 58s
Job: unit-and-integration (node-version: 22.x)  ✓ 3m 05s

Summary:
  ✓ lint                        (1 job)  0m 45s
  ✓ unit-and-integration        (3 jobs) 3m 12s
  ✓ e2e                         (1 job)  4m 30s
  ✓ build                       (1 job)  1m 20s


5. deploy.yml: النشر التلقائي إلى Vercel

بيئة النشر شروط التشغيل الهدف
Preview إنشاء/تحديث PR النشر إلى فرع المعاينة
Production الدمج في main تحديث بيئة الإنتاج
Staging وسم release التحقق قبل الإصدار

(1) إعدادات نشر Vercel

YAML
# .github/workflows/deploy.yml
name: Deploy to Vercel

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
  VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}

jobs:
  deploy-preview:
    name: Deploy Preview
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    timeout-minutes: 15
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Vercel CLI
        run: npm install --global vercel@latest
      
      - name: Pull Vercel Environment
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Build Project Artifacts
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Deploy to Vercel Preview
        run: |
          vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt
          echo "PREVIEW_URL=$(cat deployment-url.txt)" >> $GITHUB_ENV
      
      - name: Comment Preview URL on PR
        uses: thollander/actions-comment-pull-request@v2
        with:
          message: |
            🚀 **Preview Deployment Ready**
            
            | Environment | URL |
            |:-----------|:----|
            | Preview | ${{ env.PREVIEW_URL }} |
            | Branch | ${{ github.head_ref }} |
            
            _This comment is automatically updated on each push._

  deploy-production:
    name: Deploy Production
    if: github.event_name == 'push' && github.ref == 'refs/heads/main'
    needs: [deploy-preview]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    environment: production
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Vercel CLI
        run: npm install --global vercel@latest
      
      - name: Pull Vercel Environment
        run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Build Project Artifacts
        run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Deploy to Vercel Production
        run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }}
      
      - name: Notify deployment success
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "✅ Production deployment completed: ${{ github.repository }}@${{ github.sha }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}


6. بناء صورة Docker (متعدد المراحل، 358 MB)

للنشر الذاتي (self-hosting)، تحتاج إلى بناء صور Docker تلقائيا في CI.

(1) Dockerfile متعدد المراحل

DOCKERFILE
# Dockerfile — Next.js 16 standalone بناء صورة
# المرحلة 1: تثبيت التبعيات (باستخدام طبقة التخزين المؤقت)
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production && \
    npm cache clean --force

# المرحلة 2: البناء (توليد مخرجات .next)
FROM node:20-alpine AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

# المرحلة 3: التشغيل (صورة مصغرة ~358MB)
FROM node:20-alpine AS runner
WORKDIR /app

ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1

RUN addgroup --system --gid 1001 nodejs && \
    adduser --system --uid 1001 nextjs

COPY --from=build /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static

USER nextjs

EXPOSE 3000

ENV PORT=3000
ENV HOSTNAME="0.0.0.0"

CMD ["node", "server.js"]

(2) Docker Build Action

YAML
# .github/workflows/docker.yml
name: Docker Build & Push

on:
  push:
    tags: ['v*']
  schedule:
    - cron: '0 2 * * 0'  # الأحد المبكر الساعة 2 صباحا

jobs:
  docker:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
      
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3
      
      - name: Login to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      
      - name: Docker meta
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha,format=short
            type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
      
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

▶ مثال: مخرجات بناء صورة Docker

TEXT 📖 للعرض فقط
# سجل البناء
#1 [deps 1/1] RUN npm ci --only=production
#1 DONE 15.2s

#2 [build 1/4] COPY --from=deps /app/node_modules ./node_modules
#2 DONE 0.1s

#3 [build 2/4] COPY . .
#3 DONE 0.3s

#4 [build 3/4] RUN npm run build
#4 DONE 28.5s

#5 [runner 1/6] COPY --from=build /app/public ./public
#5 DONE 0.1s

#6 Exporting layers
#6 DONE 3.2s

# تحليل حجم الصورة
ghcr.io/myorg/taskflow:latest   358 MB


7. متغيرات البيئة وإدارة الأسرار

100%
graph TB
    A[GitHub Secrets] --> B[بيئة تشغيل Actions]
    B --> C[Vercel Token]
    B --> D[رابط قاعدة البيانات]
    B --> E[مفاتيح API]
    B --> F[Slack Webhook]
    C --> G[النشر إلى Vercel]
    D --> H[تشغيل الاختبار]
    E --> I[الحقن أثناء البناء]
    F --> J[إشعار النشر]
    
    style A fill:#cce5ff
    style B fill:#d4edda
اسم متغير البيئة الغرض المصدر
VERCEL_TOKEN مصادقة Vercel API GitHub Secrets
VERCEL_ORG_ID معرف فريق Vercel لوحة تحكم Vercel
VERCEL_PROJECT_ID معرف مشروع Vercel لوحة تحكم Vercel
DATABASE_URL اتصال قاعدة البيانات GitHub Secrets
CODECOV_TOKEN رفع تغطية الاختبار موقع Codecov
SLACK_WEBHOOK_URL إشعار النشر إعدادات تطبيق Slack

(1) إعداد GitHub Secrets

BASH
# في مستودع GitHub ← Settings → Secrets and variables → Actions ← Add

gh secret set VERCEL_TOKEN --body "your-vercel-token"
gh secret set DATABASE_URL --body "postgresql://user:pass@host:5432/db"
gh secret set SLACK_WEBHOOK_URL --body "https://hooks.slack.com/services/..."

(2) استراتيجية عزل البيئات

YAML
# تجاوز المتغيرات في البيئات المختلفة
jobs:
  test:
    env:
      DATABASE_URL: postgresql://test:test@localhost:5432/testdb
      NODE_ENV: test
      
  deploy-preview:
    environment: preview
    env:
      DATABASE_URL: ${{ secrets.PREVIEW_DATABASE_URL }}
      NEXT_PUBLIC_API_URL: ${{ vars.PREVIEW_API_URL }}
      
  deploy-production:
    environment: production
    env:
      DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
      NEXT_PUBLIC_API_URL: https://api.taskflow.io


8. سير عمل نشر معاينة PR

تتيح معاينة PR للمطورين معاينة تأثير تغييراتهم قبل الدمج.

100%
graph TB
    A[المطور ينشئ PR] --> B[Actions تشغل deploy-preview]
    B --> C[Vercel تنشئ نشر معاينة]
    C --> D[توليد رابط المعاينة]
    D --> E[البوت يعلق على PR برابط]
    E --> F[المراجع يتحقق من المعاينة]
    F -->|موافقة| G[الدمج في main]
    G --> H[Actions تشغل deploy-production]
    
    style A fill:#cce5ff
    style F fill:#fff3cd
    style H fill:#d4edda

▶ مثال: سير عمل معاينة PR كامل + التنظيف

المخرجات:

TEXT 📖 للعرض فقط
احفظ إعدادات YAML أعلاه في مسار الملف المحدد. ستصبح الإعدادات سارية عند إعادة تشغيل الخادم التالية.
YAML
# .github/workflows/preview.yml
name: PR Preview

on:
  pull_request:
    types: [opened, synchronize, closed]

jobs:
  preview:
    if: github.event.action != 'closed'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Vercel Preview
        id: deploy
        run: |
          npx vercel --token=${{ secrets.VERCEL_TOKEN }} \
            --scope=${{ secrets.VERCEL_ORG_ID }} \
            --confirm > preview-url.txt
          echo "url=$(cat preview-url.txt)" >> $GITHUB_OUTPUT
      
      - name: Comment URL
        uses: actions/github-script@v7
        with:
          script: |
            const url = '${{ steps.deploy.outputs.url }}'
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: `🚀 **Preview deployed**\n\n${url}\n\n_Commit: ${context.sha}_`
            })

  cleanup:
    if: github.event.action == 'closed'
    runs-on: ubuntu-latest
    steps:
      - name: Remove Vercel Preview
        run: |
          npx vercel remove \
            taskflow-git-${GITHUB_HEAD_REF//\//-} \
            --token=${{ secrets.VERCEL_TOKEN }} \
            --yes --scope=${{ secrets.VERCEL_ORG_ID }} || true

المخرجات:

TEXT 📖 للعرض فقط
Sections: name, on, jobs.


9. مثال كامل: خط تجميع CI/CD الكامل لـ TaskFlow

YAML
# .github/workflows/full-pipeline.yml
# ============================================
# خط تجميع CI/CD الكامل لـ TaskFlow
# ============================================
name: TaskFlow Full Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  release:
    types: [published]

env:
  NODE_VERSION: '20'
  PNPM_VERSION: '9'

jobs:
  # === المرحلة 1: بوابة الجودة ===
  quality-gate:
    name: Quality Gate
    runs-on: ubuntu-latest
    timeout-minutes: 10
    
    steps:
      - uses: actions/checkout@v4
      
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      
      - name: TypeScript check
        run: pnpm typecheck
        
      - name: ESLint + Prettier
        run: pnpm lint && pnpm format:check
        
      - name: Unit tests with coverage
        run: pnpm test:coverage
        
      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          token: ${{ secrets.CODECOV_TOKEN }}
          fail_ci_if_error: false

  # === المرحلة 2: اختبار التكامل ===
  integration:
    name: Integration Tests
    needs: [quality-gate]
    runs-on: ubuntu-latest
    timeout-minutes: 20
    
    services:
      postgres:
        image: postgres:16-alpine
        env:
          POSTGRES_USER: taskflow
          POSTGRES_PASSWORD: taskflow
          POSTGRES_DB: taskflow_test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      - run: npx prisma generate
      - run: npx prisma migrate deploy
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test
      
      - name: Integration tests
        run: pnpm test:integration
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test
      
      - name: E2E tests
        run: npx playwright install --with-deps chromium && pnpm test:e2e
        env:
          DATABASE_URL: postgresql://taskflow:taskflow@localhost:5432/taskflow_test

  # === المرحلة 3: البناء ===
  build:
    name: Build Application
    needs: [integration]
    runs-on: ubuntu-latest
    timeout-minutes: 15
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
    
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: ${{ env.PNPM_VERSION }}
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'pnpm'
      
      - run: pnpm install --frozen-lockfile
      - run: pnpm build
      
      - name: Build Docker image
        if: github.event_name == 'push'
        uses: docker/build-push-action@v5
        with:
          context: .
          load: true
          tags: taskflow:ci-${{ github.sha }}
      
      - name: Save build outputs
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts
          path: |
            .next/
            public/
            package.json

  # === المرحلة 4: النشر ===
  deploy:
    name: Deploy
    needs: [build]
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    timeout-minutes: 15
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Vercel
        run: |
          npx vercel deploy --prod \
            --token=${{ secrets.VERCEL_TOKEN }} \
            --scope=${{ secrets.VERCEL_ORG_ID }}
      
      - name: Notify Slack
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "✅ TaskFlow deployed to production\nCommit: ${{ github.sha }}\nBy: ${{ github.actor }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
      
      - name: Run Lighthouse CI
        run: npx lhci autorun
        env:
          LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_TOKEN }}

❓ أسئلة شائعة

س هل الحصة المجانية لـ GitHub Actions كافية؟
ج توفر خطة GitHub Free 2,000 دقيقة شهريا من وقت تشغيل Actions (غير محدودة للمستودعات العامة). يستغرق خط تجميع CI النموذجي لـ Next.js حوالي 8-12 دقيقة لكل تشغيل، لذا يمكن لـ 2,000 دقيقة دعم حوالي 200 تشغيل شهريا. إذا احتجت المزيد، توفر GitHub Team 3,000 دقيقة شهريا، أو يمكنك إعداد runners ذاتية الاستضافة.
س لماذا من الضروري إجراء اختبار المصفوفة عبر إصدارات Node.js المتعددة؟
ج قد يكون مستخدموك يشغلون تطبيقك على إصدارات Node مختلفة (Vercel تستخدم 18.x، بينما Docker قد تستخدم 20.x أو 22.x). يضمن اختبار المصفوفة أن الكود الخاص بك يعمل بشكل صحيح على جميع إصدارات Node المدعومة. يدعم Next.js 16 رسميا Node 18.17 وما بعده؛ واختبار أحدث ثلاثة إصدارات LTS هو أفضل ممارسة.
س أيهما أفضل، vercel-action أم Vercel CLI؟
ج vercel-action (amondnet/vercel-action) يغلف عمليات CLI الشائعة، لكن التحديثات قد تتأخر. نوصي باستخدام Vercel CLI (npm install -g vercel) مباشرة؛ استخدام run: vercel deploy --prod --token=... في Actions يوفر مرونة أكبر ويضمن حصولك على أحدث إصدار.
س كيف يمكنني حماية الأسرار من التسرب؟
ج (1) استخدم GitHub Encrypted Secrets بدلا من تخزينها كنص عادي في YAML؛ (2) عطل الحقن التلقائي للأسرار لطلبات السحب من الفروع الخارجية (Settings ← Actions ← Fork pull request workflows)؛ (3) قم بتدوير الأسرار بانتظام؛ (4) استخدم actions/secrets-scanning لاكتشاف commits العرضية.
س ما الفرق بين معاينة PR ومعاينة Vercel الافتراضية؟
ج Vercel تنشئ تلقائيا نشر معاينة لكل PR (متكاملة مع Git)، لكنك تحتاج إلى تسجيل الدخول إلى لوحة تحكم Vercel لعرض الرابط. من خلال النشر اليدوي عبر GitHub Actions وتعليق الرابط في PR، يمكن لأعضاء الفريق النقر للوصول مباشرة من صفحة PR، مما يوفر تجربة أفضل.
س كيف يمكنني تحسين خط تجميع CI البطيء؟
ج (1) استخدم actions/cache لتخزين node_modules و .next/cache مؤقتا؛ (2) شغل المهام المستقلة بالتوازي؛ (3) استخدم fail-fast: false لمنع فشل إصدار واحد من إلغاء خط التجميع بأكمله؛ (4) استخدم pnpm بدلا من npm (لتثبيت أسرع)؛ (5) استضف runner ذاتيا (إذا كان المستودع كبيرا).

📖 ملخص


📝 تمارين

  1. مسألة أساسية (⭐): أنشئ .github/workflows/ci.yml يحتوي على ثلاث مهام متسلسلة — Lint و Test و Build — وشغلها عند كل push إلى main.

  2. تمرين متقدم (⭐⭐): أعد خط تجميع نشر Vercel التلقائي الكامل لمشروعك: (1) اضبط VERCEL_TOKEN في GitHub Secrets؛ (2) اكتب deploy.yml لتنفيذ معاينة PR ونشر الإنتاج؛ (3) تحقق من ظهور رابط المعاينة في تعليقات PR.

  3. تحد (⭐⭐⭐): نفذ خط تجميع CI/CD متعدد البيئات (dev ← staging ← production): (1) لكل بيئة قاعدة بياناتها وأسرارها الخاصة؛ (2) فرع dev ينشر تلقائيا إلى بيئة dev؛ (3) فرع main ينشر تلقائيا إلى staging؛ (4) النشر إلى production يتطلب موافقة يدوية؛ (5) أبلغ قناة Slack عبر webhook بعد نجاح النشر.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%