النشر
انشر باستخدام text build --adapter static أو bun أو vercel أو cloudflare، أو شغّل text start خلف وكيل.
ينتج الأمر text build دليل dist/ قابلًا للنقل. ويحوّله محوّل إلى المخرجات التي تتوقعها المنصة.
المحوّلات
text build --adapter <name>| المحوّل | المخرجات | التشغيل |
|---|---|---|
| (بلا محوّل) | dist/ + dist/.text/server | text start (Node) |
static | dist/ | أي استضافة ثابتة |
bun | dist/server.js | bun dist/server.js |
vercel | .vercel/output | Vercel (واجهة Build Output API v3) |
cloudflare | dist/ + _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. استخدمه في حاوية:
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.func | middleware لتوجيه 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.js | middleware، وإعادات الكتابة، ومعالجات المسارات، ومستند وحدة التحكم |
_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/، فاضبط الإعدادات → وقت التشغيل → السماح / المنع عند الفشل على المنع عند الفشل.
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:
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*) فتُحوّل بدقة.