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.
Терминальные HTTP-клиенты получают первый кадр страницы в виде ANSI-текста с цветами truecolor вместо HTML-документа. Ничего настраивать не нужно.
curl https://my-app.example.com/aboutЗапросы, получающие кадр
Запрос получает кадр, если выполнены все условия:
- метод —
GETилиHEAD; User-Agentначинается сcurl/,Wget/,wget2/,HTTPie/илиxh/;- заголовок
Acceptотсутствует или не содержитtext/html.
Браузеры, поисковые роботы и сервисы предпросмотра ссылок получают HTML-страницу. Чтобы получить HTML через curl, запросите его:
curl -H 'Accept: text/html' https://my-app.example.com/aboutКадр выбирается в момент, когда должна быть отдана страница: после middleware, rewrites и обработчиков маршрутов, но никогда для файлов или путей, последний сегмент которых содержит точку. Перенаправления middleware, ответы 401, заголовки и перезаписи применяются к curl так же, как к браузерам. /api/health по-прежнему запускает свой обработчик, а /robots.txt по-прежнему отдаёт файл.
Содержимое кадра
Кадр — это результат первого рендеринга страницы, как в оболочке с пререндерингом: каждая граница <Suspense>, которая ещё ожидает завершения, показывает свой fallback. Асинхронные серверные компоненты не запускаются, а fetch() никогда не завершается, поэтому данные, загружаемые в эффектах, остаются в состоянии загрузки.
- Размер: 80 × 24 ячейки. Приложение с фиксированной областью просмотра (
viewport.responsive: false) использует вместо этогоviewport.width × viewport.height. - Цвета: 24-битные управляющие последовательности SGR в теме
viewport.themeприложения. Каждая строка заканчивается сбросом оформления, а кадр заканчивается переводом строки. - Статус:
200или404со страницей приложения «Не найдено», если ни одна страница не подходит или страница вызываетnotFound(). Страница, вызывающаяredirect()во время рендеринга, отдаёт HTML.
Ответы имеют тип text/plain; charset=utf-8 с заголовками Vary: User-Agent, Accept и Cache-Control: private, no-cache, no-store, max-age=0, must-revalidate, поэтому общие кеши никогда не сохраняют кадр и не отдают его браузеру. HTML-страница по пути, где curl получает кадр, содержит тот же заголовок Vary.
Поддерживаемые среды
| Хост | Статические страницы | Динамические страницы, неизвестные пути |
|---|---|---|
text dev | Рендеринг по запросу | Рендеринг по запросу |
text start, bun | Пререндеринг через text build | Рендеринг по запросу |
vercel, cloudflare | Пререндеринг через text build | HTML-страница |
static | HTML-страница | HTML-страница |
Для страниц, отрендеренных на сервере, нужен text start или bun (см. Развёртывание).
Статические хостинги не могут отвечать разным клиентам по-разному, поэтому адаптер static не поддерживает кадры. На Vercel и Cloudflare кадры статических страниц поставляются со сборкой. Динамические страницы ([id], force-dynamic) там отдают HTML, поскольку адаптеры vercel и cloudflare не развёртывают рендерер.
text start и bun dist/server.js рендерят остальные страницы по запросу через .text/server/live.mjs и хранят последние 128 кадров в течение 10 секунд. Каждый сервер рендерит не более 20 некешированных страниц за 10 секунд. После этого curl получает HTML-страницу, пока лимит не восстановится. Если live.mjs не удаётся загрузить на сервере, например потому, что модуль страницы обращается к window на верхнем уровне, эти страницы отдают HTML.
text build сообщает о кадрах, прошедших пререндеринг:
✓ Prerendering curl frames (5/5)Настройка
Измените размер для всего приложения или отключите кадры:
import { defineConfig } from "@textjs/app";export default defineConfig({ ansi: { cols: 100, rows: 30 }, // ansi: false,});Страница может изменить собственный размер или отдавать HTML и терминалам:
export const ansi = { cols: 120, rows: 40 };// export const ansi = false;Размеры ограничены диапазоном 1–500 ячеек. При ansi: false в text.config.ts экспорты страниц игнорируются.
Обычный HTTP
curl не следует перенаправлениям, если не передать -L. Vercel перенаправляет запросы с http:// на https://, как и Cloudflare при включённом параметре Всегда использовать HTTPS, поэтому curl http://… выводит перенаправление вместо кадра. Делитесь URL с https://.
Собственные серверы
@textjs/app/ansi экспортирует вспомогательные функции распознавания запросов и формирования ответов для серверов и функций, которые не запускают text start или адаптер:
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) также принимает (method, headers) с веб-интерфейсом Headers или IncomingHttpHeaders из Node. frameToAnsi(buffer, { theme }) кодирует отрендеренный CellBuffer так же, как это делает фреймворк.