نشر تطبيق Next.js على AWS باستخدام SST Ion: دليل شامل للحوسبة السحابية بدون خوادم

Noqta Team
بواسطة Noqta Team ·

جاري تحميل مشغل تحويل النص إلى كلام الصوتي...

المقدمة

نشر تطبيق Next.js على AWS كان تقليدياً يعني ربط CloudFront وLambda@Edge وS3 وكومة من ملفات YAML في Terraform أو CloudFormation. يعمل الأمر — لكنه بطيء وهش ومؤلم عند التعديل.

SST Ion (الإصدار 3) يغير قواعد اللعبة. هو إطار عمل مفتوح المصدر يتيح لك تعريف بنيتك التحتية بالكامل على AWS بلغة TypeScript، بجانب كود التطبيق مباشرة. ملف واحد، لغة واحدة، بدون YAML. ينشر تطبيق Next.js الخاص بك على CloudFront + S3 + Lambda باستخدام OpenNext تحت الغطاء، مما يمنحك إعداداً جاهزاً للإنتاج بدون خوادم بأمر واحد.

في هذا الدليل ستتعلم كيفية:

  • تهيئة SST في مشروع Next.js
  • النشر على AWS مع CloudFront وS3 وLambda
  • إضافة رفع ملفات عبر S3 باستخدام روابط موقعة مسبقاً
  • دمج DynamoDB لتخزين البيانات بدون خوادم
  • استخدام التطوير المباشر على Lambda للحصول على ملاحظات فورية
  • إعداد النطاقات المخصصة ومراحل الإنتاج
  • إدارة بيئات متعددة (تطوير، اختبار، إنتاج)

المتطلبات الأساسية

قبل البدء، تأكد من توفر:

  • Node.js 20+ مثبت
  • AWS CLI مُعدّ مع بيانات الاعتماد (aws configure)
  • حساب AWS بصلاحيات المسؤول (أو على الأقل صلاحيات IAM وS3 وCloudFront وLambda وDynamoDB)
  • معرفة أساسية بـ Next.js App Router وTypeScript
  • محرر أكواد (يُنصح بـ VS Code)

ينشر SST موارد حقيقية على AWS قد تترتب عليها تكاليف. الموارد في هذا الدليل تبقى ضمن الطبقة المجانية لـ AWS في معظم الحالات، لكن راقب دائماً لوحة الفواتير.

ما الذي ستبنيه

بنهاية هذا الدليل، سيكون لديك:

  • تطبيق Next.js منشور على AWS عبر CloudFront (شبكة توصيل محتوى عالمية)
  • رفع ملفات مدعوم بـ S3 مع روابط موقعة مسبقاً
  • جدول DynamoDB لتخزين البيانات
  • بيئة تطوير Lambda مباشرة مع إعادة تحميل فورية
  • بيئات اختبار وإنتاج منفصلة
  • نطاق مخصص مع شهادة SSL تلقائية

الخطوة 1: إنشاء مشروع Next.js

ابدأ بإنشاء تطبيق Next.js جديد:

npx create-next-app@latest sst-nextjs-app
cd sst-nextjs-app

اختر الخيارات التالية عند السؤال:

  • TypeScript: نعم
  • ESLint: نعم
  • Tailwind CSS: نعم
  • مجلد src/: نعم
  • App Router: نعم
  • اختصار الاستيراد: @/*

الخطوة 2: تهيئة SST

ثبّت SST في المشروع:

npx sst@latest init

عند السؤال، اختر aws كمزود. يُنشئ هذا ملف sst.config.ts في جذر المشروع:

/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: "sst-nextjs-app",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: ["production"].includes(input?.stage),
      home: "aws",
    };
  },
  async run() {
    new sst.aws.Nextjs("MyWeb");
  },
});

لنفصّل ما يحدث هنا:

  • app() يُعدّ اسم التطبيق وسياسة الحذف والمزود الرئيسي
  • removal: "retain" يحتفظ بالموارد عند حذف مرحلة الإنتاج (شبكة أمان)
  • protect يمنع الحذف العرضي لموارد الإنتاج
  • async run() يُعرّف البنية التحتية — حالياً موقع Next.js فقط
  • sst.aws.Nextjs ينشر تطبيقك باستخدام OpenNext (CloudFront + S3 + Lambda)

ينشئ SST أيضاً مجلد .sst/ للأنواع والحالة. أضفه إلى .gitignore:

echo ".sst" >> .gitignore

الخطوة 3: النشر على AWS (النشر الأول)

انشر التطبيق على مرحلة التطوير:

npx sst deploy --stage dev

يستغرق النشر الأول من 3 إلى 5 دقائق لتوفير CloudFront وS3 وLambda. عمليات النشر اللاحقة أسرع بكثير. عند الانتهاء، يعرض SST رابط CloudFront:

✓  Complete
   MyWeb: https://d1234abcd.cloudfront.net

افتح الرابط — تطبيقك يعمل الآن على AWS.

كل مرحلة تحصل على مجموعة معزولة خاصة من موارد AWS. يمكنك إنشاء أي عدد من المراحل: dev، staging، production، pr-123، إلخ.

الخطوة 4: إضافة رفع الملفات عبر S3

لنضف حاوية S3 لرفع الملفات ونربطها بتطبيق Next.js.

4.1 تحديث إعدادات SST

عدّل sst.config.ts لإضافة حاوية S3 عامة:

/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: "sst-nextjs-app",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: ["production"].includes(input?.stage),
      home: "aws",
    };
  },
  async run() {
    const bucket = new sst.aws.Bucket("Uploads", {
      access: "public",
    });
 
    new sst.aws.Nextjs("MyWeb", {
      link: [bucket],
    });
 
    return {
      bucket: bucket.name,
    };
  },
});

خاصية link هي سحر SST. تمنح وظائف خادم Next.js صلاحيات IAM للحاوية وتحقن اسم الحاوية كمتغير بيئة — بدون سياسات IAM يدوية أو ملفات .env.

4.2 تثبيت AWS SDK وSST SDK

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner sst

4.3 إنشاء مسار API للرفع

أنشئ Server Action يولّد رابطاً موقعاً مسبقاً للرفع المباشر إلى S3:

// src/app/api/upload/route.ts
import { Resource } from "sst";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { NextResponse } from "next/server";
 
const s3 = new S3Client({});
 
export async function POST(request: Request) {
  const { filename, contentType } = await request.json();
 
  const key = `uploads/${Date.now()}-${filename}`;
 
  const command = new PutObjectCommand({
    Bucket: Resource.Uploads.name,
    Key: key,
    ContentType: contentType,
  });
 
  const presignedUrl = await getSignedUrl(s3, command, {
    expiresIn: 3600,
  });
 
  return NextResponse.json({
    presignedUrl,
    key,
    publicUrl: `https://${Resource.Uploads.name}.s3.amazonaws.com/${key}`,
  });
}

لاحظ Resource.Uploads.name — يحقن SST اسم الحاوية المرتبطة تلقائياً. بدون قيم ثابتة، بدون متغيرات بيئة للإدارة.

4.4 إنشاء واجهة الرفع

// src/app/upload/page.tsx
"use client";
 
import { useState } from "react";
 
export default function UploadPage() {
  const [file, setFile] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);
  const [uploadedUrl, setUploadedUrl] = useState<string | null>(null);
 
  async function handleUpload() {
    if (!file) return;
    setUploading(true);
 
    try {
      const res = await fetch("/api/upload", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          filename: file.name,
          contentType: file.type,
        }),
      });
      const { presignedUrl, publicUrl } = await res.json();
 
      await fetch(presignedUrl, {
        method: "PUT",
        headers: { "Content-Type": file.type },
        body: file,
      });
 
      setUploadedUrl(publicUrl);
    } catch (error) {
      console.error("فشل الرفع:", error);
    } finally {
      setUploading(false);
    }
  }
 
  return (
    <div className="max-w-md mx-auto p-8">
      <h1 className="text-2xl font-bold mb-4">رفع الملفات</h1>
      <input
        type="file"
        onChange={(e) => setFile(e.target.files?.[0] || null)}
        className="mb-4 block w-full"
      />
      <button
        onClick={handleUpload}
        disabled={!file || uploading}
        className="bg-blue-600 text-white px-4 py-2 rounded disabled:opacity-50"
      >
        {uploading ? "جارٍ الرفع..." : "رفع إلى S3"}
      </button>
 
      {uploadedUrl && (
        <div className="mt-4 p-4 bg-green-50 rounded">
          <p className="text-sm text-green-800">تم الرفع بنجاح!</p>
          <a
            href={uploadedUrl}
            target="_blank"
            rel="noopener noreferrer"
            className="text-blue-600 underline text-sm break-all"
          >
            {uploadedUrl}
          </a>
        </div>
      )}
    </div>
  );
}

الخطوة 5: إضافة DynamoDB لتخزين البيانات

5.1 تعريف الجدول في إعدادات SST

حدّث sst.config.ts لإضافة جدول DynamoDB:

/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: "sst-nextjs-app",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: ["production"].includes(input?.stage),
      home: "aws",
    };
  },
  async run() {
    const bucket = new sst.aws.Bucket("Uploads", {
      access: "public",
    });
 
    const table = new sst.aws.Dynamo("Notes", {
      fields: {
        userId: "string",
        noteId: "string",
      },
      primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
    });
 
    new sst.aws.Nextjs("MyWeb", {
      link: [bucket, table],
    });
 
    return {
      bucket: bucket.name,
      table: table.name,
    };
  },
});

5.2 تثبيت عميل DynamoDB

npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb

5.3 إنشاء API الملاحظات

// src/app/api/notes/route.ts
import { Resource } from "sst";
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import {
  DynamoDBDocumentClient,
  PutCommand,
  QueryCommand,
} from "@aws-sdk/lib-dynamodb";
import { NextResponse } from "next/server";
 
const client = DynamoDBDocumentClient.from(new DynamoDBClient({}));
 
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const userId = searchParams.get("userId") || "anonymous";
 
  const result = await client.send(
    new QueryCommand({
      TableName: Resource.Notes.name,
      KeyConditionExpression: "userId = :userId",
      ExpressionAttributeValues: { ":userId": userId },
    })
  );
 
  return NextResponse.json({ notes: result.Items || [] });
}
 
export async function POST(request: Request) {
  const { userId = "anonymous", title, content } = await request.json();
 
  const note = {
    userId,
    noteId: `note_${Date.now()}`,
    title,
    content,
    createdAt: new Date().toISOString(),
  };
 
  await client.send(
    new PutCommand({
      TableName: Resource.Notes.name,
      Item: note,
    })
  );
 
  return NextResponse.json({ note });
}

5.4 إنشاء صفحة الملاحظات

// src/app/notes/page.tsx
"use client";
 
import { useEffect, useState } from "react";
 
interface Note {
  noteId: string;
  title: string;
  content: string;
  createdAt: string;
}
 
export default function NotesPage() {
  const [notes, setNotes] = useState<Note[]>([]);
  const [title, setTitle] = useState("");
  const [content, setContent] = useState("");
 
  async function loadNotes() {
    const res = await fetch("/api/notes?userId=anonymous");
    const data = await res.json();
    setNotes(data.notes);
  }
 
  async function createNote() {
    if (!title || !content) return;
 
    await fetch("/api/notes", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ title, content }),
    });
 
    setTitle("");
    setContent("");
    loadNotes();
  }
 
  useEffect(() => {
    loadNotes();
  }, []);
 
  return (
    <div className="max-w-2xl mx-auto p-8">
      <h1 className="text-2xl font-bold mb-6">ملاحظات بدون خوادم</h1>
 
      <div className="mb-8 space-y-3">
        <input
          type="text"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="عنوان الملاحظة"
          className="w-full border rounded px-3 py-2"
        />
        <textarea
          value={content}
          onChange={(e) => setContent(e.target.value)}
          placeholder="محتوى الملاحظة"
          className="w-full border rounded px-3 py-2 h-24"
        />
        <button
          onClick={createNote}
          className="bg-blue-600 text-white px-4 py-2 rounded"
        >
          إضافة ملاحظة
        </button>
      </div>
 
      <div className="space-y-4">
        {notes.map((note) => (
          <div key={note.noteId} className="border rounded p-4">
            <h2 className="font-semibold">{note.title}</h2>
            <p className="text-gray-600 mt-1">{note.content}</p>
            <p className="text-xs text-gray-400 mt-2">{note.createdAt}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

الخطوة 6: التطوير المباشر على Lambda

هنا يتألق SST حقاً. بدلاً من إعادة النشر في كل مرة تُغيّر كود الخادم، يوجّه sst dev استدعاءات Lambda إلى جهازك المحلي في الوقت الفعلي.

ابدأ بيئة التطوير:

npx sst dev

يقوم SST بثلاثة أشياء في وقت واحد:

  1. نشر البنية التحتية على AWS (S3، DynamoDB، CloudFront)
  2. توجيه طلبات Lambda إلى جهازك المحلي (إعادة تحميل فورية)
  3. تشغيل خادم تطوير Next.js على localhost:3000

غيّر مسار API، احفظ الملف، وأعد التحميل — التغيير فوري. بدون إعادة نشر، بدون انتظار. هذا ممكن لأن SST يستبدل دالة Lambda بوكيل يُعيد توجيه الاستدعاءات إلى جهازك عبر اتصال WebSocket.

يتطلب التطوير المباشر على Lambda أن تكون بيانات AWS الخاصة بك مُعدّة. ينشئ SST اتصال WebSocket خفيف عبر IoT للتوجيه — كودك يعمل محلياً لكنه يصل إلى موارد AWS الحقيقية.

الخطوة 7: إعداد النطاق المخصص

7.1 باستخدام Route 53

إذا كان نطاقك مُداراً عبر Route 53، أضف خيار domain لمكون Nextjs:

new sst.aws.Nextjs("MyWeb", {
  link: [bucket, table],
  domain: {
    name: "app.yourdomain.com",
    dns: sst.aws.dns(),
  },
});

ينشئ SST تلقائياً سجلات Route 53 ويوفر شهادة SSL عبر ACM.

7.2 باستخدام Cloudflare DNS

للنطاقات المُدارة عبر Cloudflare:

new sst.aws.Nextjs("MyWeb", {
  link: [bucket, table],
  domain: {
    name: "app.yourdomain.com",
    dns: sst.cloudflare.dns(),
  },
});

7.3 باستخدام DNS خارجي

لمزودين آخرين، يعرض SST سجلات DNS المطلوبة وينتظرك لإعدادها:

new sst.aws.Nextjs("MyWeb", {
  link: [bucket, table],
  domain: {
    name: "app.yourdomain.com",
    dns: false,
  },
});

الخطوة 8: الإعدادات حسب البيئة

تتيح مراحل SST إنشاء بيئات معزولة. استخدم متغير $app.stage لإعداد الموارد بشكل مختلف لكل مرحلة:

async run() {
  const isProd = $app.stage === "production";
 
  const bucket = new sst.aws.Bucket("Uploads", {
    access: "public",
  });
 
  const table = new sst.aws.Dynamo("Notes", {
    fields: {
      userId: "string",
      noteId: "string",
    },
    primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
    pointInTimeRecovery: isProd,
  });
 
  new sst.aws.Nextjs("MyWeb", {
    link: [bucket, table],
    domain: isProd
      ? { name: "app.yourdomain.com", dns: sst.aws.dns() }
      : undefined,
    server: {
      memory: isProd ? "1024 MB" : "512 MB",
    },
  });
}

النشر على مراحل مختلفة:

# التطوير
npx sst deploy --stage dev
 
# الاختبار
npx sst deploy --stage staging
 
# الإنتاج
npx sst deploy --stage production

كل مرحلة تُنشئ موارد معزولة تماماً — حاويات S3 منفصلة، جداول DynamoDB، توزيعات CloudFront، ودوال Lambda.

الخطوة 9: إضافة مهمة مجدولة

يُسهّل SST إضافة المهام المجدولة. لنضف مهمة يومية لتنظيف الملفات القديمة:

// أضف إلى sst.config.ts داخل async run()
new sst.aws.Cron("CleanupOldUploads", {
  schedule: "rate(1 day)",
  job: {
    handler: "src/functions/cleanup.handler",
    link: [bucket],
  },
});

أنشئ المعالج:

// src/functions/cleanup.ts
import { Resource } from "sst";
import {
  S3Client,
  ListObjectsV2Command,
  DeleteObjectsCommand,
} from "@aws-sdk/client-s3";
 
const s3 = new S3Client({});
const DAYS_TO_KEEP = 30;
 
export async function handler() {
  const cutoff = new Date();
  cutoff.setDate(cutoff.getDate() - DAYS_TO_KEEP);
 
  const objects = await s3.send(
    new ListObjectsV2Command({
      Bucket: Resource.Uploads.name,
      Prefix: "uploads/",
    })
  );
 
  const toDelete = (objects.Contents || [])
    .filter((obj) => obj.LastModified && obj.LastModified < cutoff)
    .map((obj) => ({ Key: obj.Key! }));
 
  if (toDelete.length > 0) {
    await s3.send(
      new DeleteObjectsCommand({
        Bucket: Resource.Uploads.name,
        Delete: { Objects: toDelete },
      })
    );
    console.log(`تم حذف ${toDelete.length} ملفات قديمة`);
  }
 
  return { deleted: toDelete.length };
}

الخطوة 10: النشر للإنتاج

10.1 إعدادات SST النهائية

هذا هو ملف sst.config.ts الكامل مع جميع الموارد:

/// <reference path="./.sst/platform/config.d.ts" />
export default $config({
  app(input) {
    return {
      name: "sst-nextjs-app",
      removal: input?.stage === "production" ? "retain" : "remove",
      protect: ["production"].includes(input?.stage),
      home: "aws",
    };
  },
  async run() {
    const isProd = $app.stage === "production";
 
    const bucket = new sst.aws.Bucket("Uploads", {
      access: "public",
    });
 
    const table = new sst.aws.Dynamo("Notes", {
      fields: {
        userId: "string",
        noteId: "string",
      },
      primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
      pointInTimeRecovery: isProd,
    });
 
    new sst.aws.Nextjs("MyWeb", {
      link: [bucket, table],
      domain: isProd
        ? { name: "app.yourdomain.com", dns: sst.aws.dns() }
        : undefined,
      server: {
        memory: isProd ? "1024 MB" : "512 MB",
        architecture: "arm64",
      },
    });
 
    new sst.aws.Cron("CleanupOldUploads", {
      schedule: "rate(1 day)",
      job: {
        handler: "src/functions/cleanup.handler",
        link: [bucket],
      },
    });
 
    return {
      bucket: bucket.name,
      table: table.name,
    };
  },
});

10.2 النشر للإنتاج

npx sst deploy --stage production

10.3 مراقبة النشر

يعرض SST جميع تفاصيل الموارد بعد النشر. يمكنك أيضاً عرضها في وحدة تحكم AWS:

  • CloudFront — توزيع CDN والنطاق
  • S3 — حاوية الرفع والأصول الثابتة
  • Lambda — دوال الخادم
  • DynamoDB — جدول البيانات

10.4 حذف مرحلة

لهدم مرحلة غير إنتاجية وحذف جميع مواردها:

npx sst remove --stage dev

مراحل الإنتاج مع protect: true لا يمكن حذفها عرضياً. يجب أولاً تعيين protect إلى false في الإعدادات قبل الحذف.

استكشاف الأخطاء

خطأ "Cannot find module 'sst'" في Next.js

تأكد من تثبيت حزمة sst:

npm install sst

النشر الأول بطيء

يوفر النشر الأولي توزيع CloudFront، مما يستغرق من 3 إلى 5 دقائق. عمليات النشر اللاحقة أسرع بكثير (عادة أقل من 60 ثانية).

أخطاء "Access Denied"

تأكد من أن بيانات AWS لديك تملك صلاحيات كافية. يحتاج SST للوصول إلى IAM وS3 وCloudFront وLambda وDynamoDB وCloudWatch وSSM على الأقل. يُنصح باستخدام دور المسؤول للتطوير.

التطوير المباشر لا يتصل

تأكد من صلاحية بيانات AWS وأن المنفذ 443 الصادر غير محظور بجدار الحماية. يستخدم SST خدمة AWS IoT Core لاتصال WebSocket.

SST مقابل خيارات النشر الأخرى

الميزةSST IonVercelAWS CDKTerraform
اللغةTypeScriptغير متاح (واجهة)TypeScriptHCL
التطوير المباشرنعم (أقل من ثانية)لالالا
ربط المواردتلقائيمتغيرات بيئة يدويةيدوييدوي
التكلفةأسعار AWS فقطلكل مقعد + استخدامأسعار AWSأسعار AWS
دعم Next.jsكامل (OpenNext)أصلييدوييدوي
تعدد المزودينأكثر من 150 مزودVercel فقطAWS فقطأكثر من 150

الخطوات التالية

الآن بعد أن لديك تطبيق Next.js متكامل على AWS، فكّر في:

  • إضافة المصادقة مع sst.aws.Cognito أو دمج NextAuth.js
  • إعداد خط أنابيب CI/CD مع GitHub Actions يشغّل npx sst deploy --stage production
  • إضافة بوابة API مع sst.aws.ApiGatewayV2 لواجهات برمجة مستقلة
  • استكشاف وحدة تحكم SST على console.sst.dev للوحة بصرية لمواردك
  • إضافة طابور مع sst.aws.Queue للمعالجة في الخلفية

الخلاصة

يحوّل SST Ion نشر AWS من صداع DevOps إلى تجربة صديقة للمطورين. بتعريف البنية التحتية بـ TypeScript بجانب كود التطبيق، تحصل على أمان الأنواع وربط الموارد والتطوير المباشر — كل ذلك أثناء النشر على حساب AWS الخاص بك بدون رسوم إضافية.

النقاط الرئيسية:

  • البنية التحتية ككود بـ TypeScript — بدون YAML، بدون ملفات إعدادات منفصلة
  • ربط الموارد يلغي سياسات IAM اليدوية ومتغيرات البيئة
  • التطوير المباشر على Lambda يوفر ملاحظات فورية بدون إعادة نشر
  • المراحل تمنحك بيئات معزولة مجاناً
  • OpenNext ينشر Next.js على AWS بدعم كامل للميزات

يتيح لك SST امتلاك بنيتك التحتية بدون تعقيدات AWS التقليدية. ابدأ بـ npx sst@latest init وانشر تطبيقك الأول في دقائق.


هل تريد قراءة المزيد من الدروس التعليمية؟ تحقق من أحدث درس تعليمي لدينا على بناء تطبيق ويب تقدمي (PWA) باستخدام Next.js App Router.

ناقش مشروعك معنا

نحن هنا للمساعدة في احتياجات تطوير الويب الخاصة بك. حدد موعدًا لمناقشة مشروعك وكيف يمكننا مساعدتك.

دعنا نجد أفضل الحلول لاحتياجاتك.

مقالات ذات صلة

Neon Serverless Postgres مع Next.js App Router: بناء تطبيق كامل مع تفريع قواعد البيانات

تعلّم كيفية بناء تطبيق Next.js كامل مدعوم بقاعدة بيانات Neon Serverless Postgres. يغطي هذا الدليل التطبيقي برنامج التشغيل بدون خادم، تفريع قواعد البيانات لعمليات النشر التجريبية، تجميع الاتصالات، وأنماط الإنتاج الجاهزة.

28 د قراءة·

بناء مهام خلفية للإنتاج باستخدام Trigger.dev v3 و Next.js

تعلم كيفية بناء مهام خلفية موثوقة ومهام مجدولة وسير عمل متعدد الخطوات باستخدام Trigger.dev v3 مع Next.js. يغطي هذا الدرس إنشاء المهام ومعالجة الأخطاء وإعادة المحاولة والمهام المجدولة والنشر في بيئة الإنتاج.

28 د قراءة·