デプロイ

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.jsCloudflare Pages

アダプターは TEXTJS_ADAPTER でも指定できます。Vercel(VERCEL=1)またはCloudflare Pages(CF_PAGES=1)で text build を実行すると、対応するアダプターが自動的に選択されます。

サーバーアダプター(bun、vercel、cloudflare)は text start と同じパイプラインを実行します。ミドルウェア、rewrites、ルートキャッシュを使用するルートハンドラー、静的アセット、そしてページURL用のコンソールドキュメントの順です。curlなどのターミナルクライアントには、代わりにページの最初のフレームをANSIテキストとして返します。vercel と cloudflare では、これは静的ページのみが対象です(curlとターミナルクライアントを参照)。サーバーアダプターは /assets/ 配下のハッシュ付きファイルを Cache-Control: public, max-age=31536000, immutable 付きで配信します。

静的配信

text build --adapter static

GitHub Pages、S3、CDNなど、サーバーのないホストで使用します。dynamic = "force-static" または revalidate を持つ GET ルートハンドラーはファイルにプリレンダリングされ、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/ は配信しません。長時間稼働するプロセスなので、text start と同様にサーバーレンダリングされるルート(export const runtime = "server")とそのライブセッションもホストします。コンテナーで使用するには、次のようにします。

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

Vercel

text build --adapter vercelvercel deploy --prebuilt

または、Vercelに接続されたGitリポジトリーにプッシュします。ビルドで text build が実行され、Vercelを検出して .vercel/output を書き出します。

出力内容
static/クライアントのビルド(basePath 配下)
functions/_textjs/server.funcすべてのルートハンドラーをストリーミング付きで処理する1つのNode.js 22関数
functions/_middleware.funcEdge Routing Middleware:middleware.ts と、すべてのアプリの正規パス
config.jsonアセットヘッダー、ミドルウェアのマッチャー、リライト、ハンドラールート、コンソールドキュメント

エッジミドルウェアは x-middleware-next / x-middleware-rewrite プロトコルを使用するため、関数やCDNに到達する前にVercelのルーターでヘッダーの上書きとリライトが処理されます。すべてのマッチャーは1つのルート src パターンを共有します。どのマッチャーにも該当しないリクエストは、パスが正規形式でない可能性がある場合(パーセントエスケープ、URLパーサーがエンコードする文字、//、. または .. セグメント、末尾のスラッシュ)を除き、ミドルウェアをスキップします。その場合、ミドルウェアは正規パスを照合し、has / missing を確認し、Vercelが同じ方法でルーティングするようにリクエストをそのパスに書き換えます。middleware.ts のないアプリにも同じエッジ関数が含まれ、リライトのみを処理します。すべてのビルドにエッジ関数が含まれるため、ログイン済みのVercelアカウントからデプロイしてください。匿名デプロイ(vercel deploy --temporary)ではエッジ関数を受け付けません。

ハンドラー関数は内部用です。各ハンドラールートは、一致したパスを x-textjs-path リクエストヘッダーでこの関数に渡します。このヘッダーはミドルウェアの前後ですべてのリクエストから削除され、エッジミドルウェアも(クライアント由来でも middleware.ts 由来でも)転送しないため、設定できるのはハンドラールートだけです。/_textjs/* へのリクエストは、ミドルウェアとリライトの前後で、関数を実行せずに 404 を返します。生成されたルートは、ほかのすべてのホストのマッチャーやリライトと同様に、大文字と小文字を区別して照合されます。

アダプターのテストでは、この出力をVercelのルーターのローカルエミュレーションで実行します。src の照合、dest のキャプチャー、ヘッダー変換、status ルートの動作は実際のデプロイで検証済みですが、エッジミドルウェアは匿名でデプロイできないため検証していません。

Cloudflare Pages

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

出力はPagesのアドバンストモードを使用します。

ファイル用途
_worker.jsミドルウェア、リライト、ルートハンドラー、コンソールドキュメント
_routes.jsonすべてのリクエストをワーカーへ送信(ミドルウェアも basePath もない場合、/assets/* はPagesの静的CDNから配信)
_headers/assets/* の不変キャッシュ設定(既存の設定に追記)
404.html存在しないファイルに対し、アプリではなく 404 を返す(既存のファイルは保持)

Pagesはディレクトリーをそのまま公開するため、.text/(サーバーバンドルとビルドマニフェスト)は dist/ から削除されます。

Pagesプロジェクト(「設定」→「ランタイム」)または wrangler.toml で互換性フラグ nodejs_compat を有効にしてください。データキャッシュは AsyncLocalStorage を使用します。静的ファイルは ASSETS バインディングを通じて配信され、バックグラウンドでの再検証には ctx.waitUntil() が使用されます。

ミドルウェアがある場合、ファイルに到達可能なすべてのパスをミドルウェアが確認できるように、ハッシュ付きアセットを含むすべてのリクエストでワーカーが実行されます。ワーカーを実行するリクエストはそれぞれ1回のFunctions呼び出しとなり、Workersのリクエスト割り当てにカウントされます。ページの読み込みでは、ドキュメントと取得する各ファイルが対象です(JavaScriptバンドルが1つの小さなテストアプリでは2、ファイルが多いアプリではそれ以上)。Workers Freeプランでは、1日の割り当てを使い切ると、Pagesはワーカーを使わずに静的ファイルを配信するため、ミドルウェアがスキップされます。ミドルウェアで 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:_worker.js と _routes.json を含む新しい dist/ をデプロイします。
  • Bun:新しい dist/ 全体(server.js、アセット、ライブバンドル)をデプロイし、サーバーを再起動します。
  • text start:text build を実行し、再起動します。

古いデプロイは、それぞれのURL(たとえばVercelやCloudflare PagesのプレビューURL)で引き続きアクセス可能です。削除するか、プラットフォームのアクセス保護を適用してください。

サーバーレンダリングされるルート

サーバーレンダリングされるルートは開いているタブごとにセッションを保持するため、長時間稼働するサーバーが必要です。text start または bun アダプターを使用します。static、vercel、cloudflare アダプターでは、ページが runtime = "server" をエクスポートすると、TX030 でビルドが失敗します。

プロキシの背後での実行

text start は 127.0.0.1 にバインドし、ループバックにバインドしている間は localhost、*.localhost、IPアドレスのホストにのみ応答します(DNSリバインディング対策)。ほかのホストには TX028 付きの 403 を返します。公開用の設定を 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 で構築されます。

注意点

  • text.config.ts の proxy は text dev と text start でのみ実行され、アダプターには含まれません。すべてのサーバーアダプターが対応する rewrites を使用してください。
  • サーバーレスインスタンスは、それぞれ独自のインメモリーキャッシュを持ちます。キャッシュを参照してください。
  • 正規表現のグループを直接使用する rewrites は、ベストエフォートでVercelのルートに変換されます。名前付きパラメーター(:slug、:path*)は正確に変換されます。
GitHubでこのページを編集