النشر

انشر باستخدام ⁦text build --adapter static⁩ أو bun أو vercel أو cloudflare، أو شغّل ⁦text start⁩ خلف وكيل.

ينتج الأمر text build دليل dist/ قابلًا للنقل. ويحوّله محوّل إلى المخرجات التي تتوقعها المنصة.

المحوّلات

text build --adapter <name>
المحوّلالمخرجاتالتشغيل
(بلا محوّل)dist/ + dist/.text/servertext start (Node)
staticdist/أي استضافة ثابتة
bundist/server.jsbun dist/server.js
vercel.vercel/outputVercel (واجهة ⁦Build Output API v3⁩)
cloudflaredist/ + _worker.js⁦Cloudflare Pages⁩

يمكن أيضًا تحديد المحوّل عبر TEXTJS_ADAPTER. عند تشغيل text build على Vercel (VERCEL=1) أو ⁦Cloudflare Pages⁩ (CF_PAGES=1)، يُختار المحوّل المطابق تلقائيًا.

تشغّل محوّلات الخادم (bun و vercel و cloudflare) مراحل المعالجة نفسها التي يشغّلها text start: middleware، ثم rewrites، ثم معالجات المسارات مع ذاكرة التخزين المؤقت للمسارات، ثم الأصول الثابتة، ثم مستند وحدة التحكم لعناوين URL الخاصة بالصفحات. وتتلقى عملاء الطرفية مثل curl الإطار الأول للصفحة كنص ANSI بدلًا من ذلك. في vercel و cloudflare، يقتصر ذلك على الصفحات الثابتة (راجع curl وعملاء الطرفية). تقدّم محوّلات الخادم الملفات ذات الأسماء المتضمنة قيم تجزئة ضمن /assets/ مع Cache-Control: public, max-age=31536000, immutable.

الاستضافة الثابتة

text build --adapter static

استخدمه للاستضافات التي لا تتضمن خادمًا، مثل ⁦GitHub Pages⁩ أو ⁦S3⁩ أو شبكة CDN. تُعرض معالجات مسارات GET التي تتضمن dynamic = "force-static" أو revalidate مسبقًا في ملفات: يتحوّل app/api/feed.json/route.ts إلى dist/api/feed.json. وتُكتب نسخة من index.html في 404.html لتفتح الروابط العميقة تطبيق وحدة التحكم. لا تستطيع الاستضافات الثابتة التمييز بين curl والمتصفح، لذا يتلقى curl صفحة HTML.

يفشل البناء مع سرد كل الأسباب إذا احتاج التطبيق إلى خادم: middleware.ts، أو مسارات معروضة على الخادم، أو معالجات مسارات ديناميكية، أو معالجات مسارات ذات مقاطع ديناميكية، أو طرق غير GET. اضبط rewrites على الاستضافة بدلًا من ذلك.

Bun

text build --adapter bunPORT=8080 bun dist/server.js

يكتب المحوّل bun خادمًا واحدًا مستقلًا لا يحتاج إلى node_modules وقت التشغيل. ويقرأ PORT (القيمة الافتراضية 3000) و HOSTNAME (القيمة الافتراضية 0.0.0.0)، ولا يقدّم server.js أو .text/ مطلقًا. وهو عملية طويلة العمر، لذا يستضيف أيضًا المسارات المعروضة على الخادم (export const runtime = "server") وجلساتها الحية، مثل text start. استخدمه في حاوية:

Dockerfiletext
FROM oven/bun:1COPY dist /appCMD ["bun", "/app/server.js"]

Vercel

text build --adapter vercelvercel deploy --prebuilt

أو ادفع التغييرات إلى مستودع Git متصل بمنصة Vercel: يشغّل البناء الأمر text build، ويكتشف Vercel ويكتب .vercel/output.

المخرجاتالمحتويات
static/بناء العميل (ضمن basePath)
functions/_textjs/server.funcدالة ⁦Node.js 22⁩ واحدة تخدم كل معالجات المسارات، مع البث
functions/_middleware.funcmiddleware لتوجيه Edge: الملف middleware.ts، والمسارات القياسية لكل تطبيق
config.jsonترويسات الأصول، ومطابقات middleware، وإعادات الكتابة، ومسارات المعالجات، ومستند وحدة التحكم

تستخدم ⁦edge middleware⁩ بروتوكول x-middleware-next / x-middleware-rewrite، لذا تحدث تجاوزات الترويسات وإعادات الكتابة في موجّه Vercel قبل الوصول إلى الدالة أو شبكة CDN. تشترك كل المطابقات في نمط مسار src واحد. تتجاوز الطلبات التي لا تغطيها أي مطابقة middleware، إلا إذا كان مسارها قد لا يكون بالصيغة القياسية (ترميزات النسبة المئوية، أو محارف يرمّزها محلّل URL، أو مقاطع // أو . أو ..، أو شرطة مائلة ختامية). تطابق middleware عندئذ المسار القياسي، وتتحقق من has / missing، وتعيد كتابة الطلب إلى ذلك المسار كي توجّهه Vercel بالطريقة نفسها. تحصل التطبيقات التي لا تتضمن middleware.ts على دالة edge نفسها، التي تنفّذ إعادة الكتابة فقط. ولأن كل بناء يتضمن دالة Edge، انشر من حساب Vercel مسجّل الدخول: لا تقبل عمليات النشر المجهولة (vercel deploy --temporary) دوال Edge.

دالة المعالج داخلية. يمرّر كل مسار معالج المسار المطابق إليها في ترويسة الطلب x-textjs-path. تُزال هذه الترويسة من كل طلب قبل middleware وبعدها، ولا تمرّر ⁦edge middleware⁩ أي ترويسة منها مطلقًا (من العميل أو من middleware.ts)، لذا لا يمكن إلا لمسارات المعالجات تعيينها. تعيد طلبات /_textjs/* الرمز 404 دون تشغيل الدالة، قبل middleware وإعادات الكتابة وبعدها. تراعي مطابقة المسارات المولّدة حالة الأحرف، مثل المطابقات وإعادات الكتابة على كل الاستضافات الأخرى.

تشغّل اختبارات المحوّل هذه المخرجات مقابل محاكاة محلية لموجّه Vercel. وقد جرى التحقق من سلوكه في مطابقة src، والتقاطات dest، وتحويلات الترويسات، ومسارات status مقابل عمليات نشر فعلية؛ ولم يجرِ التحقق من ⁦Edge middleware⁩ لتعذّر نشرها دون تسجيل الدخول.

Cloudflare Pages

text build --adapter cloudflarebunx wrangler pages dev dist --compatibility-flags=nodejs_compatbunx wrangler pages deploy dist

تستخدم المخرجات الوضع المتقدم في Pages:

الملفالغرض
_worker.jsmiddleware، وإعادات الكتابة، ومعالجات المسارات، ومستند وحدة التحكم
_routes.jsonإرسال كل طلب إلى العامل. في غياب middleware أو basePath، يبقى /assets/* على شبكة CDN الثابتة الخاصة بمنصة Pages
_headersتخزين مؤقت غير قابل للتغيير للمسار /assets/* (يُلحق بملفك)
404.htmlجعل Pages تردّ على الملفات المفقودة بالرمز 404 بدلًا من التطبيق (يُحتفظ به إن كان موجودًا لديك)

يُحذف .text/ (حزم الخادم وملفات بيان البناء) من dist/، لأن Pages تنشر الدليل كما هو.

فعّل علامة التوافق nodejs_compat في مشروع Pages (الإعدادات → وقت التشغيل) أو في wrangler.toml؛ تستخدم ذاكرة التخزين المؤقت للبيانات AsyncLocalStorage. تُقدّم الملفات الثابتة عبر الربط ASSETS، وتستخدم إعادة التحقق في الخلفية ctx.waitUntil().

مع middleware، يشغّل كل طلب العامل، بما في ذلك الأصول ذات الأسماء المتضمنة قيم تجزئة، كي ترى middleware كل مسار يمكن الوصول إلى ملف من خلاله. يُعدّ كل طلب يشغّل العامل استدعاءً واحدًا لخدمة Functions ويُحتسب ضمن حصة طلبات Workers. عند تحميل صفحة، يشمل ذلك المستند وكل ملف يجلبه (2 لتطبيق اختبار صغير بحزمة JavaScript واحدة؛ وأكثر للتطبيقات ذات الملفات الأكثر). في خطة ⁦Workers Free⁩، تقدّم Pages الملفات الثابتة دون العامل عند نفاد الحصة اليومية، مما يتجاوز middleware. إذا كانت middleware تحمي أي شيء في dist/، فاضبط الإعدادات → وقت التشغيل → السماح / المنع عند الفشل على المنع عند الفشل.

wrangler.tomltoml
name = "my-console"pages_build_output_dir = "dist"compatibility_date = "2025-01-01"compatibility_flags = ["nodejs_compat"]

الترقية

لا تصل إصلاحات الأمان في @textjs/app إلى نسخة منشورة إلا بعد إعادة بنائها ونشرها:

  • ⁦Vercel⁩: انشر .vercel/output الجديد.
  • ⁦Cloudflare Pages⁩: انشر dist/ الجديد، مع _worker.js و _routes.json.
  • Bun: انشر dist/ الجديد كاملًا (server.js، والأصول، والحزم الحية) وأعد تشغيل الخادم.
  • text start: شغّل text build وأعد التشغيل.

تبقى النسخ المنشورة الأقدم متاحة عبر عناوين URL الخاصة بها (مثل عناوين المعاينة في Vercel و ⁦Cloudflare Pages⁩). احذفها أو ضعها خلف حماية الوصول الخاصة بالمنصة.

المسارات المعروضة على الخادم

تحتفظ المسارات المعروضة على الخادم بجلسة لكل علامة تبويب مفتوحة، لذا تحتاج إلى خادم طويل العمر: text start أو المحوّل bun. تُفشل المحوّلات static و vercel و cloudflare البناء بالرمز TX030 عندما تصدّر صفحة runtime = "server".

العمل خلف وكيل

يرتبط text start بالعنوان 127.0.0.1، وأثناء ارتباطه بعنوان الاسترجاع لا يستجيب إلا للمضيفين localhost و *.localhost والمضيفين ذوي عناوين IP (حماية من إعادة ربط DNS). يتلقى المضيفون الآخرون الرمز 403 مع TX028. ضع الإعدادات العامة في text.config.ts:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  server: {    origin: "https://console.example.com", // request.url always uses it (or TEXTJS_ORIGIN)    trustProxy: true, // read X-Forwarded-Host / -Proto from your proxy (or TRUST_PROXY=1)    allowedHosts: [".example.com"],  },});

في غياب origin أو trustProxy، يُبنى request.url من ترويسة Host التي جرى التحقق منها عبر http.

محاذير

  • لا يعمل proxy في text.config.ts إلا في text dev و text start؛ ولا تتضمنه المحوّلات. استخدم rewrites التي يدعمها كل محوّل خادم.
  • لكل نسخة تشغيل بلا خادم ذاكرة تخزين مؤقت خاصة بها في الذاكرة. راجع التخزين المؤقت.
  • تُحوّل rewrites التي تستخدم مجموعات تعبيرات نمطية خام إلى مسارات Vercel بأفضل جهد ممكن؛ أما المعاملات المسماة (:slug، :path*) فتُحوّل بدقة.
تحرير هذه الصفحة على GitHub