Deploy

Esegui il deploy con text build --adapter static, bun, vercel o cloudflare, oppure esegui text start dietro un proxy.

text build produce una dist/ portabile. Un adattatore la converte nell’output previsto da una piattaforma.

Adattatori

text build --adapter <name>
AdattatoreOutputEsecuzione
(nessuno)dist/ + dist/.text/servertext start (Node)
staticdist/Qualsiasi host statico
bundist/server.jsbun dist/server.js
vercel.vercel/outputVercel (Build Output API v3)
cloudflaredist/ + _worker.jsCloudflare Pages

L’adattatore può anche essere specificato tramite TEXTJS_ADAPTER. Quando text build viene eseguito su Vercel (VERCEL=1) o Cloudflare Pages (CF_PAGES=1), l’adattatore corrispondente viene selezionato automaticamente.

Gli adattatori server (bun, vercel e cloudflare) eseguono la stessa pipeline di text start: middleware, rewrites, route handler con la cache delle route, risorse statiche, poi il documento della console per gli URL delle pagine. I client da terminale come curl ricevono invece il primo frame della pagina come testo ANSI. Su vercel e cloudflare questo vale solo per le pagine statiche (vedi curl e client da terminale). Gli adattatori server servono i file con hash sotto /assets/ con Cache-Control: public, max-age=31536000, immutable.

Statico

text build --adapter static

Usalo per host senza server, come GitHub Pages, S3 o una CDN. I route handler GET con dynamic = "force-static" o revalidate vengono sottoposti a pre-rendering in file: app/api/feed.json/route.ts diventa dist/api/feed.json. Una copia di index.html viene scritta in 404.html affinché i deep link aprano l’app nella console. Gli host statici non distinguono curl da un browser, quindi curl riceve la pagina HTML.

La build fallisce, elencando ogni motivo, se l’app richiede un server: middleware.ts, route renderizzate lato server, route handler dinamici, route handler con segmenti dinamici o metodi diversi da GET. Configura invece rewrites sull’host.

Bun

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

L’adattatore bun scrive un unico server autonomo che non richiede node_modules in fase di esecuzione. Legge PORT (valore predefinito 3000) e HOSTNAME (valore predefinito 0.0.0.0) e non serve mai server.js o .text/. È un processo di lunga durata, quindi ospita anche le route renderizzate lato server (export const runtime = "server") e le loro sessioni attive, come text start. Usalo in un container:

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

Vercel

text build --adapter vercelvercel deploy --prebuilt

Oppure esegui un push su un repository Git collegato a Vercel: la build esegue text build, rileva Vercel e scrive .vercel/output.

OutputContenuto
static/La build client (sotto basePath)
functions/_textjs/server.funcUna funzione Node.js 22 che serve ogni route handler, con streaming
functions/_middleware.funcMiddleware di routing Edge: middleware.ts e percorsi canonici per ogni app
config.jsonHeader delle risorse, matcher del middleware, riscritture, route degli handler e documento della console

Il middleware edge usa il protocollo x-middleware-next / x-middleware-rewrite, quindi le sovrascritture degli header e le riscritture avvengono nel router di Vercel prima di raggiungere la funzione o la CDN. Tutti i matcher condividono un unico pattern src di route. Le richieste non coperte da alcun matcher saltano il middleware, a meno che il loro percorso possa non essere in forma canonica (escape percentuali, caratteri codificati da un parser URL, //, segmenti . o .., una barra finale). Il middleware confronta quindi il percorso canonico, verifica has / missing e riscrive la richiesta verso quel percorso affinché Vercel la instradi allo stesso modo. Le app senza middleware.ts ricevono la stessa edge function, che esegue solo la riscrittura. Poiché ogni build include una funzione Edge, esegui il deploy da un account Vercel autenticato: i deploy anonimi (vercel deploy --temporary) non accettano funzioni Edge.

La funzione handler è interna. Ogni route handler le passa il percorso corrispondente nell’header di richiesta x-textjs-path. Questo header viene rimosso da ogni richiesta prima e dopo il middleware, e il middleware edge non ne inoltra mai uno (dal client o da middleware.ts), quindi solo le route degli handler possono impostarlo. Le richieste per /_textjs/* restituiscono 404 senza eseguire la funzione, prima e dopo il middleware e le riscritture. Le route generate distinguono tra maiuscole e minuscole, come i matcher e le riscritture su ogni altro host.

I test dell’adattatore eseguono questo output su un’emulazione locale del router di Vercel. Il comportamento per la corrispondenza di src, le catture di dest, le trasformazioni degli header e le route status è stato verificato su deploy reali; il middleware Edge no, perché non può essere distribuito in modo anonimo.

Cloudflare Pages

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

L’output usa la modalità avanzata di Pages:

FileScopo
_worker.jsMiddleware, riscritture, route handler e documento della console
_routes.jsonInvia ogni richiesta al worker. Senza middleware o un basePath, /assets/* resta sulla CDN statica di Pages
_headersCache immutabile per /assets/* (accodata ai tuoi header)
404.htmlFa rispondere Pages con 404 per i file mancanti invece che con l’app (mantenuto se ne hai uno)

.text/ (bundle server e manifest della build) viene rimosso da dist/, poiché Pages pubblica la directory così com’è.

Abilita il flag di compatibilità nodejs_compat nel progetto Pages (Settings → Runtime) o in wrangler.toml; la cache dei dati usa AsyncLocalStorage. I file statici vengono serviti tramite il binding ASSETS e la riconvalida in background usa ctx.waitUntil().

Con il middleware, ogni richiesta esegue il worker, incluse le risorse con hash, affinché il middleware veda ogni percorso attraverso cui un file è raggiungibile. Ogni richiesta che esegue il worker è un’invocazione di Functions e viene conteggiata nella tua quota di richieste Workers. Per il caricamento di una pagina, si tratta del documento più ogni file che recupera (2 per una piccola app di test con un bundle JavaScript; di più per app con più file). Nel piano Workers Free, Pages serve i file statici senza il worker una volta esaurita la quota giornaliera, saltando il middleware. Se il middleware protegge qualcosa in dist/, imposta Settings → Runtime → Fail open / closed su Fail closed.

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

Aggiornamento

Le correzioni di sicurezza in @textjs/app raggiungono un deploy solo dopo che hai ricompilato l’app ed eseguito nuovamente il deploy:

  • Vercel: esegui il deploy del nuovo .vercel/output.
  • Cloudflare Pages: esegui il deploy della nuova dist/, con _worker.js e _routes.json.
  • Bun: esegui il deploy dell’intera nuova dist/ (server.js, risorse e bundle live) e riavvia il server.
  • text start: esegui text build e riavvia.

I deploy precedenti restano raggiungibili ai rispettivi URL (per esempio gli URL di anteprima di Vercel e Cloudflare Pages). Eliminali o proteggili con i controlli di accesso della piattaforma.

Route renderizzate lato server

Le route renderizzate lato server mantengono una sessione per ogni scheda aperta, quindi richiedono un server di lunga durata: text start o l’adattatore bun. Gli adattatori static, vercel e cloudflare fanno fallire la build con TX030 quando una pagina esporta runtime = "server".

Dietro un proxy

text start si associa a 127.0.0.1 e, mentre è associato al loopback, risponde solo a localhost, *.localhost e host con indirizzo IP (protezione dal DNS rebinding). Gli altri host ricevono un 403 con TX028. Inserisci le impostazioni pubbliche in 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"],  },});

Senza origin o trustProxy, request.url viene costruito dall’header Host convalidato usando http.

Avvertenze

  • proxy in text.config.ts viene eseguito solo in text dev e text start; gli adattatori non lo includono. Usa rewrites, supportato da ogni adattatore server.
  • Ogni istanza serverless ha la propria cache in memoria. Vedi Cache.
  • Le rewrites che usano gruppi grezzi di espressioni regolari vengono convertite in route Vercel nei limiti del possibile; i parametri con nome (:slug, :path*) hanno una corrispondenza esatta.
Modifica questa pagina su GitHub