Deployen
Deploye mit text build --adapter static, bun, vercel oder cloudflare, oder führe text start hinter einem Proxy aus.
text build erzeugt ein portables dist/. Ein Adapter wandelt es in die Ausgabe um, die eine Plattform erwartet.
Adapter
text build --adapter <name>| Adapter | Ausgabe | Ausführung |
|---|---|---|
| (keiner) | dist/ + dist/.text/server | text start (Node) |
static | dist/ | Jeder statische Host |
bun | dist/server.js | bun dist/server.js |
vercel | .vercel/output | Vercel (Build Output API v3) |
cloudflare | dist/ + _worker.js | Cloudflare Pages |
Der Adapter kann auch über TEXTJS_ADAPTER festgelegt werden. Wenn text build auf Vercel (VERCEL=1) oder Cloudflare Pages (CF_PAGES=1) läuft, wird automatisch der passende Adapter ausgewählt.
Die Server-Adapter (bun, vercel und cloudflare) führen dieselbe Pipeline wie text start aus: Middleware, rewrites, Route-Handler mit dem Route-Cache, statische Assets und dann das Konsolendokument für Seiten-URLs. Terminal-Clients wie curl erhalten stattdessen den ersten Frame der Seite als ANSI-Text. Auf vercel und cloudflare gilt das nur für statische Seiten (siehe curl und Terminal-Clients). Die Server-Adapter liefern Dateien mit Hash im Namen unter /assets/ mit Cache-Control: public, max-age=31536000, immutable aus.
Statisch
text build --adapter staticVerwende diesen Adapter für Hosts ohne Server, etwa GitHub Pages, S3 oder ein CDN. GET-Route-Handler mit dynamic = "force-static" oder revalidate werden per Prerendering in Dateien umgewandelt: Aus app/api/feed.json/route.ts wird dist/api/feed.json. Eine Kopie von index.html wird in 404.html geschrieben, damit Deep-Links die Konsolen-App öffnen. Statische Hosts können curl nicht von einem Browser unterscheiden, daher erhält curl die HTML-Seite.
Der Build schlägt fehl und listet alle Gründe auf, wenn die App einen Server benötigt: middleware.ts, serverseitig gerenderte Routen, dynamische Route-Handler, Route-Handler mit dynamischen Segmenten oder andere Methoden als GET. Konfiguriere rewrites stattdessen auf dem Host.
Bun
text build --adapter bunPORT=8080 bun dist/server.jsDer bun-Adapter schreibt einen einzelnen, eigenständigen Server, der zur Laufzeit keine node_modules benötigt. Er liest PORT (Standard 3000) und HOSTNAME (Standard 0.0.0.0) und liefert niemals server.js oder .text/ aus. Er läuft als langlebiger Prozess und hostet daher wie text start auch serverseitig gerenderte Routen (export const runtime = "server") und deren Live-Sitzungen. Verwende ihn in einem Container:
FROM oven/bun:1COPY dist /appCMD ["bun", "/app/server.js"]Vercel
text build --adapter vercelvercel deploy --prebuiltOder pushe in ein mit Vercel verbundenes Git-Repository: Der Build führt text build aus, erkennt Vercel und schreibt .vercel/output.
| Ausgabe | Inhalt |
|---|---|
static/ | Der Client-Build (unter basePath) |
functions/_textjs/server.func | Eine Node.js 22-Funktion, die alle Route-Handler bedient, mit Streaming |
functions/_middleware.func | Edge-Routing-Middleware: middleware.ts und kanonische Pfade für jede App |
config.json | Asset-Header, Middleware-Matcher, Rewrites, Handler-Routen und das Konsolendokument |
Die Edge-Middleware verwendet das Protokoll x-middleware-next / x-middleware-rewrite, sodass Header-Überschreibungen und Rewrites im Router von Vercel stattfinden, bevor die Funktion oder das CDN erreicht wird. Alle Matcher teilen sich ein src-Muster für Routen. Anfragen, die kein Matcher abdeckt, überspringen die Middleware, es sei denn, ihr Pfad liegt möglicherweise nicht in kanonischer Form vor (Prozentkodierungen, Zeichen, die ein URL-Parser kodiert, //, .- oder ..-Segmente, ein abschließender Schrägstrich). Die Middleware gleicht dann den kanonischen Pfad ab, prüft has / missing und schreibt die Anfrage auf diesen Pfad um, damit Vercel sie genauso routet. Apps ohne middleware.ts erhalten dieselbe Edge-Funktion, die nur das Rewrite ausführt. Da jeder Build eine Edge-Funktion enthält, deploye über ein angemeldetes Vercel-Konto: Anonyme Deployments (vercel deploy --temporary) akzeptieren keine Edge-Funktionen.
Die Handler-Funktion ist intern. Jede Handler-Route übergibt ihr den übereinstimmenden Pfad im Anfrage-Header x-textjs-path. Dieser Header wird vor und nach der Middleware aus jeder Anfrage entfernt, und die Edge-Middleware leitet ihn niemals weiter (weder vom Client noch aus middleware.ts), sodass ihn nur die Handler-Routen setzen können. Anfragen an /_textjs/* geben vor und nach Middleware und Rewrites 404 zurück, ohne die Funktion auszuführen. Generierte Routen beachten die Groß- und Kleinschreibung, ebenso wie die Matcher und Rewrites auf jedem anderen Host.
Die Tests des Adapters prüfen diese Ausgabe gegen eine lokale Emulation des Vercel-Routers. Dessen Verhalten beim src-Abgleich, bei dest-Erfassungsgruppen, Header-Transformationen und status-Routen wurde anhand echter Deployments geprüft; die Edge-Middleware nicht, da sie sich nicht anonym deployen lässt.
Cloudflare Pages
text build --adapter cloudflarebunx wrangler pages dev dist --compatibility-flags=nodejs_compatbunx wrangler pages deploy distDie Ausgabe verwendet den erweiterten Modus von Pages:
| Datei | Zweck |
|---|---|
_worker.js | Middleware, Rewrites, Route-Handler und das Konsolendokument |
_routes.json | Sendet jede Anfrage an den Worker. Ohne Middleware oder basePath bleibt /assets/* auf dem statischen CDN von Pages |
_headers | Unveränderliches Caching für /assets/* (an deine Datei angehängt) |
404.html | Lässt Pages bei fehlenden Dateien mit 404 statt mit der App antworten (bleibt erhalten, falls bereits vorhanden) |
.text/ (Server-Bundles und Build-Manifeste) wird aus dist/ entfernt, da Pages das Verzeichnis unverändert veröffentlicht.
Aktiviere das Kompatibilitätsflag nodejs_compat im Pages-Projekt (Settings → Runtime) oder in wrangler.toml; der Datencache verwendet AsyncLocalStorage. Statische Dateien werden über das ASSETS-Binding ausgeliefert, und die Revalidierung im Hintergrund verwendet ctx.waitUntil().
Mit Middleware führt jede Anfrage den Worker aus, auch bei Assets mit Hash im Namen, damit die Middleware jeden Pfad sieht, über den eine Datei erreichbar ist. Jede Anfrage, die den Worker ausführt, ist ein Functions-Aufruf und zählt zu deinem Workers-Anfragekontingent. Beim Laden einer Seite sind das das Dokument und jede Datei, die es abruft (2 für eine kleine Test-App mit einem JavaScript-Bundle; mehr bei Apps mit mehr Dateien). Im Workers-Free-Tarif liefert Pages statische Dateien ohne den Worker aus, sobald das tägliche Kontingent aufgebraucht ist, und überspringt damit die Middleware. Wenn Middleware etwas in dist/ schützt, setze Settings → Runtime → Fail open / closed auf Fail closed.
name = "my-console"pages_build_output_dir = "dist"compatibility_date = "2025-01-01"compatibility_flags = ["nodejs_compat"]Aktualisieren
Sicherheitskorrekturen in @textjs/app erreichen ein Deployment erst, nachdem du es neu gebaut und erneut deployt hast:
- Vercel: Deploye das neue
.vercel/output. - Cloudflare Pages: Deploye das neue
dist/mit_worker.jsund_routes.json. - Bun: Deploye das gesamte neue
dist/(server.js, Assets und Live-Bundles) und starte den Server neu. text start: Führetext buildaus und starte neu.
Ältere Deployments bleiben unter ihren eigenen URLs erreichbar (zum Beispiel Vorschau-URLs von Vercel und Cloudflare Pages). Lösche sie oder sichere sie mit dem Zugriffsschutz der Plattform ab.
Serverseitig gerenderte Routen
Serverseitig gerenderte Routen halten für jeden offenen Tab eine Sitzung vor und benötigen daher einen langlebigen Server: text start oder den bun-Adapter. Die Adapter static, vercel und cloudflare brechen den Build mit TX030 ab, wenn eine Seite runtime = "server" exportiert.
Hinter einem Proxy
text start bindet sich an 127.0.0.1 und beantwortet bei dieser Loopback-Bindung nur Anfragen an localhost, *.localhost und Hosts mit IP-Adressen (Schutz vor DNS-Rebinding). Andere Hosts erhalten 403 mit TX028. Trage die öffentlichen Einstellungen in text.config.ts ein:
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"], },});Ohne origin oder trustProxy wird request.url aus dem validierten Host-Header mit http gebildet.
Einschränkungen
proxyintext.config.tsläuft nur intext devundtext start; Adapter enthalten es nicht. Verwenderewrites, das jeder Server-Adapter unterstützt.- Serverless-Instanzen haben jeweils ihren eigenen In-Memory-Cache. Siehe Caching.
rewrites, die rohe Gruppen regulärer Ausdrücke verwenden, werden nach bestem Bemühen in Vercel-Routen übersetzt; benannte Parameter (:slug,:path*) sind exakt.