curl and Terminal Clients

curl, Wget, HTTPie and xh get a page's first frame as truecolor ANSI text. Configure its size or turn it off.

Các HTTP client trong terminal nhận frame đầu tiên của trang dưới dạng văn bản ANSI truecolor thay vì tài liệu HTML. Bạn không cần cấu hình gì.

curl https://my-app.example.com/about

Những yêu cầu nhận frame

Một yêu cầu nhận frame khi đáp ứng tất cả điều kiện sau:

  • phương thức là GET hoặc HEAD;
  • User-Agent bắt đầu bằng curl/, Wget/, wget2/, HTTPie/ hoặc xh/;
  • không có header Accept hoặc header này không chứa text/html.

Trình duyệt, trình thu thập dữ liệu và bản xem trước liên kết nhận trang HTML. Để nhận HTML từ curl, yêu cầu rõ định dạng này:

curl -H 'Accept: text/html' https://my-app.example.com/about

Frame được chọn tại thời điểm trang sẽ được phục vụ: sau middleware, rewrites và route handler, và không bao giờ áp dụng cho tệp hoặc đường dẫn có dấu chấm trong đoạn cuối. Chuyển hướng, mã 401, header và rewrite của middleware áp dụng cho curl giống như với trình duyệt. /api/health vẫn chạy handler của nó và /robots.txt vẫn phục vụ tệp.

Nội dung trong frame

Frame là lần render đầu tiên của trang, giống như trong một shell được prerender: mỗi ranh giới <Suspense> còn đang chờ đều hiển thị fallback. Component máy chủ bất đồng bộ không chạy, và fetch() không bao giờ hoàn tất, nên dữ liệu tải trong effect vẫn ở trạng thái đang tải.

  • Kích thước: 80 × 24 ô. Ứng dụng có viewport cố định (viewport.responsive: false) dùng viewport.width × viewport.height thay thế.
  • Màu sắc: mã thoát SGR 24-bit theo viewport.theme của ứng dụng. Mỗi dòng kết thúc bằng mã đặt lại, và frame kết thúc bằng ký tự xuống dòng.
  • Trạng thái: 200, hoặc 404 kèm trang không tìm thấy của ứng dụng khi không có trang nào khớp hoặc trang gọi notFound(). Trang gọi redirect() trong lúc render sẽ phục vụ HTML.

Phản hồi có kiểu text/plain; charset=utf-8 với Vary: User-Agent, Accept và Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate, nên bộ nhớ đệm dùng chung không bao giờ lưu frame rồi phục vụ nó cho trình duyệt. Trang HTML tại đường dẫn mà curl nhận frame cũng có cùng header Vary.

Môi trường hỗ trợ

Môi trường lưu trữTrang tĩnhTrang động, đường dẫn chưa biết
text devRender khi có yêu cầuRender khi có yêu cầu
text start, bunPrerender bằng text buildRender khi có yêu cầu
vercel, cloudflarePrerender bằng text buildTrang HTML
staticTrang HTMLTrang HTML

Trang được render phía máy chủ cần text start hoặc bun (xem Triển khai).

Môi trường lưu trữ tĩnh không thể trả lời khác nhau cho từng client, nên adapter static không hỗ trợ frame. Trên Vercel và Cloudflare, frame cho trang tĩnh đi kèm bản build. Trang động ([id], force-dynamic) phục vụ HTML tại đó, vì adapter vercel và cloudflare không triển khai trình render.

text start và bun dist/server.js render những trang còn lại khi có yêu cầu bằng .text/server/live.mjs, và giữ 128 frame gần nhất trong 10 giây. Mỗi máy chủ render tối đa 20 trang chưa có trong bộ nhớ đệm mỗi 10 giây. Khi vượt mức đó, curl nhận trang HTML cho đến khi hạn mức được khôi phục. Nếu máy chủ không thể tải live.mjs, chẳng hạn vì một mô-đun trang đọc window ở cấp cao nhất, những trang đó sẽ phục vụ HTML.

text build báo cáo các frame đã prerender:

 ✓ Prerendering curl frames (5/5)

Cấu hình

Đổi kích thước cho toàn bộ ứng dụng, hoặc tắt frame:

text.config.tsts
import { defineConfig } from "@textjs/app";export default defineConfig({  ansi: { cols: 100, rows: 30 },  // ansi: false,});

Một trang có thể đổi kích thước riêng, hoặc phục vụ HTML cho cả terminal:

app/dashboard/page.tsxtsx
export const ansi = { cols: 120, rows: 40 };// export const ansi = false;

Kích thước được giới hạn trong khoảng 1–500 ô. Khi đặt ansi: false trong text.config.ts, các export của trang sẽ bị bỏ qua.

HTTP thuần

curl không theo chuyển hướng trừ khi bạn truyền -L. Vercel chuyển hướng yêu cầu http:// sang https://, và Cloudflare cũng vậy khi bật Luôn sử dụng HTTPS, nên curl http://… in ra chuyển hướng thay vì frame. Chia sẻ URL https://.

Máy chủ tùy chỉnh

@textjs/app/ansi export các hàm hỗ trợ nhận diện và phản hồi, dành cho máy chủ và hàm không chạy text start hoặc adapter:

import { ansiResponse, wantsAnsi } from "@textjs/app/ansi";import { frameToAnsi } from "@textjs/react";if (wantsAnsi(request)) return ansiResponse(frameToAnsi(buffer, { theme: "geistDark" }), request.method);

wantsAnsi(request) cũng nhận (method, headers) với Headers của Web hoặc IncomingHttpHeaders của Node. frameToAnsi(buffer, { theme }) mã hóa một CellBuffer đã render theo cùng cách với framework.

Sửa trang này trên GitHub