تخطَّ إلى المحتوى
نسخة تجريبيةشاركنا رأيك

إعدادات البناء

يُبنى كل مشروع بناءً على ما تكتشفه المنصّة في مستودعك. وحين يخطئ الاكتشاف — أو حين تفضّل أن تكون طريقة البناء مثبَّتة في الشيفرة لا في لوحة التحكّم — أودِع ملف sahabti.json فيفوز على ما عداه.

الملف اختياري، وكل حقل فيه اختياري، وهو محفوظ مع شيفرتك: فالبناء الذي ينتجه فرعٌ ما يصفه ذلك الفرع نفسه.

أين يوضع الملف

في المجلد الجذر لمشروعك — الذي حدّدته عند استيراد المستودع، وهو جذر المستودع ما لم تغيّره.

المجلد الجذرالملف
./sahabti.json
apps/webapps/web/sahabti.json

وفي أي مكان آخر لا يُقرأ.

أيّ طبقة تفوز

ثلاث طبقات، والأعلى أولاً:

  1. sahabti.json — هذا الملف.
  2. إعدادات البناء — طبقة التجاوز في لوحة تحكّم المشروع.
  3. الاكتشاف التلقائي — ما تستنتجه المنصّة وحدها.

والحسم يجري لكل حقل على حدة، لا للملف كله: فملف sahabti.json لا يحمل سوى buildCommand يثبّت أمر البناء ويترك كل ما عداه للطبقتين الأدنى. ويسمّي سجلّ البناء في كل نشر مصدرَ كل قيمة استُعملت، فيمكنك دائماً أن ترى أيّ طبقة فازت.

الحقول

json
{
  "framework": "nextjs",
  "installCommand": "pnpm install --frozen-lockfile",
  "buildCommand": "pnpm run build",
  "startCommand": "pnpm run start",
  "outputDir": "",
  "dockerfilePath": "",
  "nodeVersion": "22"
}
الحقلالقيمة
frameworkواحد من nextjs أو nuxt أو astro أو sveltekit أو react-router أو vite أو node أو python أو go أو static أو docker. وهو يتخطّى الاكتشاف لا يصحّحه — فإن لم يكن في المستودع شيء من هذا النوع فشل البناء بدل أن يخمّن من جديد.
installCommandالأمر الذي يثبّت الاعتماديات.
buildCommandالأمر الذي يبني تطبيقك.
startCommandالأمر الذي يشغّله.
outputDirالمجلد الذي يُنشر، نسبةً إلى مجلدك الجذر.
dockerfilePathابنِ ملف Dockerfile هذا بدل ملف مولَّد.
dockerfileBuildEnvinject (الافتراضي) أو verbatim — انظر ملفات Dockerfile.
nodeVersionرقم الإصدار الرئيسي، كنصّ: "22". وإلا فمن engines.node، ثم .nvmrc أو .node-version، و24 إن لم يقل شيءٌ شيئاً.

كل أمر سطر واحد. والمسارات نسبيّة إلى مجلدك الجذر — بلا / في البداية، وبلا ...

والنصّ الفارغ يعني «لا تفعل هذا إطلاقاً»، وهو غير حذف الحقل. فـ"installCommand": "" يتخطّى التثبيت، أما حذف installCommand فيدع لوحة التحكّم أو الاكتشاف تملؤه.

أمثلة

صحّح أمر البناء وحده، واترك الباقي مكتشَفاً:

json
{ "buildCommand": "pnpm run build:prod" }

الاعتماديات مرفقة في المستودع، فتخطَّ خطوة التثبيت:

json
{ "installCommand": "" }

انشر ناتج البناء موقعاً ساكناً — مجلد مخرجات بلا أمر تشغيل يعني ألّا شيء يعمل، وأن المجلد يُقدَّم ملفاتٍ كما هو:

json
{ "buildCommand": "npm run build", "startCommand": "", "outputDir": "dist" }

وجّه تطبيق Python إلى نقطة الدخول الصحيحة:

json
{ "startCommand": "gunicorn app.wsgi:application --bind 0.0.0.0:$PORT" }

وعلى تطبيقك أن يستمع إلى المنفذ الموجود في $PORT. والبناءات المولَّدة تتكفّل بذلك؛ أما منفذ مكتوب بثباتٍ في الشيفرة فيسقط في فحص السلامة الذي يحرس كل نشر.

وحزمةٌ داخل مستودع أحادي (monorepo) لا تحتاج عادةً شيئاً هنا — حدِّد المجلد الجذر في المشروع، فتُثبَّت الاعتماديات في جذر مساحة العمل ويجري البناء في حزمتك.

ما لا مكان له فيه

لا تُقرأ متغيّرات البيئة من مستودعك أبداً. فمكانها الإعدادات ← البيئة، وهناك وحدها — إذ ملف إعدادات في git يبعد دفعةً واحدة عن أن يصير سرّاً معلناً. وتصل المتغيّرات إلى البناء وإلى الحاوية العاملة من لوحة التحكّم.

كذلك يبقى المستودع والفرع والمجلد الجذر ومفتاح النشر التلقائي في لوحة التحكّم: فالمنصّة تحتاجها لتجد شيفرتك وتستنسخها قبل أن يوجد ملفٌ يُقرأ أصلاً.

ملفات Dockerfile

تحديد dockerfilePath، أو "framework": "docker" مع وجود Dockerfile في مجلدك الجذر، يبني ملف Dockerfile الخاص بك. وعندها تُهمَل الحقول installCommand وbuildCommand وstartCommand وoutputDir — فملفك هو البناء — ويقول السجلّ ذلك.

ومتغيّرات بيئتك ليست وسائط بناء، فأي ARG لا يتلقّى شيئاً من لوحة التحكّم. بل تُركَّب سرّاً للبناء، وتُهيَّأ كل خطوة RUN لقراءته، فترى خطوة البناء المتغيّرات نفسها التي ستراها الحاوية العاملة. ولا يُعدَّل ملفك المُودَع أبداً — فالتهيئة تجري على نسخة منه.

أما خطوة مكتوبة بصيغة لا يمكن تعديلها بأمان فتُترك كما كتبتها تماماً، ويسمّيها سجلّ البناء. وهذه تصلها بنفسك:

dockerfile
RUN --mount=type=secret,id=buildenv sh -c '. /run/secrets/buildenv; npm run build'

ولإبقاء ملف Dockerfile دون مساس، ابنِه كما أُودِع:

json
{ "dockerfilePath": "Dockerfile", "dockerfileBuildEnv": "verbatim" }

فلا يُضاف عندها شيء إلى أي خطوة، ولا تُضبط متغيّرات وقت البناء ما لم تركّب السرّ بنفسك.

حين يكون الملف خاطئاً

لا يُهمَل ملف sahabti.json أودعتَه إهمالاً صامتاً أبداً. فـJSON غير سليم، أو حقل غير معروف، أو قيمة لا تصلح — كلها تُسقط النشر عند خطوة اكتشاف الإطار، ويسمّي سجلّ البناء الحقل والمشكلة. ويبقى تطبيقك العامل يخدم كما هو — فبناءٌ فاشل لا يحلّ محلّه أبداً.

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