Rendering di server dalam konsol
Text.js 0.4 dapat me-render halaman di server dan mengalirkan frame-nya ke konsol sebagai delta sel. Route statis juga melakukan prerender frame pertamanya ke dalam HTML.
Text.js 0.4 menambahkan tempat kedua untuk me-render halaman. Secara default, pohon React halaman berjalan di tab browser. Halaman yang mengekspor runtime = "server" berjalan di server, dan browser menerima frame-nya.
import { Suspense, type ReactNode } from "react";import os from "node:os";import { Box, Text } from "textjs";export const runtime = "server";async function Load(): Promise<ReactNode> { const [one, five] = os.loadavg(); return <Text>{`load ${one.toFixed(2)} ${five.toFixed(2)}`}</Text>;}export default function StatusPage(): ReactNode { return ( <Box flexDirection="column"> <Text bold>Status</Text> <Suspense fallback={<Text color="gray">Reading host…</Text>}> <Load /> </Suspense> </Box> );}Load adalah komponen async function. Di server, komponen ini menangguhkan rendering ke <Suspense> atau loading.tsx terdekat hingga promise-nya selesai, dan bisa membaca file, basis data, serta modul node:* secara langsung. Komponen async memuat data dan tidak bisa menggunakan hook. Komponen biasa di sekitarnya tetap menggunakan hook, fokus, useInput, <Link>, dan useRouter(), yang berperilaku sama di kedua runtime.
Yang diunduh browser
Halaman yang di-render di server tidak mengirim React, Yoga, atau route Anda. Browser memuat pemutar frame berukuran sekitar 21 kB gzip, yang menyimpan CellBuffer dan CssConsoleDriver yang sama dengan yang digunakan renderer klien. Pemutar ini mengatur laju frame pada 15 fps yang sama, sehingga frame yang di-render di server menghasilkan panggilan console.log yang sama seperti di klien.
Protokol
Setiap tab membuka sesinya sendiri di server: root React, riwayat router dalam memori, dan buffer sel. Satu endpoint menangani kedua arah:
browser tab ──(GET /__textjs/live, server-sent events)──▶ frame deltasbrowser tab ──(POST /__textjs/live, JSON)──────────────▶ keys, paste, wheel, resize, focus, Back/ForwardServer hanya mengirim baris yang hash-nya berubah sejak frame terakhir yang diterima koneksi tersebut. Setiap baris dikirim sebagai rentetan teks yang merujuk ke tabel gaya yang hanya menerima penambahan di akhir. Grafem lebar, klaster emoji, dan warna semitransparan tiba secara utuh.
Jarak antarframe minimal 66 ms, dan setiap frame dibandingkan dengan yang terakhir diterima socket. Ketika koneksi lambat berhenti menguras buffer, state perantara dilewati, dan frame berikutnya melompat ke state terbaru.
Jika aliran terputus, pemutar menyambung kembali dengan ID sesinya di header x-textjs-live dan melanjutkan sesi yang sama dari keyframe baru, dengan state yang tetap utuh. ID sesi berupa nilai acak 192-bit yang disimpan dalam memori, tidak pernah di URL. Sesi tanpa koneksi berhenti me-render dan dilepas setelah 30 detik.
Kedua endpoint menolak permintaan lintas situs, dan setiap event input divalidasi berdasarkan skema tetap. Satu sesi menerima maksimal 64 event per POST dan sekitar 240 per detik.
Komponen async dan data
Promise setiap komponen async disimpan dalam cache per sesi, dengan komponen dan props-nya sebagai kunci, sehingga rendering yang dicoba ulang menggunakan kembali permintaan yang sedang berlangsung. Cache dibersihkan saat route berubah dan saat Anda memanggil router.refresh():
const router = useRouter();useInput((e) => e.input === "r" && router.refresh());Modul khusus server diberi nama *.server.ts. Build gagal jika kode yang dikirim ke browser mengimpor modul tersebut, atau mengimpor modul bawaan node:*, dan menyebutkan pengimpornya.
Prerender parsial
Prerender parsial bekerja tanpa server. text build kini me-render setiap route statis satu kali dan menyisipkan frame pertamanya langsung ke HTML route sebagai <script> klasik berukuran kecil, sehingga konsol menampilkan hasil sebelum modul apa pun dimuat.
Shell mencakup semua yang di-render secara sinkron. Batas <Suspense> yang masih menunggu menampilkan fallback-nya, termasuk komponen async, dan fetch() tidak pernah selesai selama shell di-render.
Saat JavaScript mulai berjalan, renderer klien atau pemutar frame mengalirkan frame yang sebenarnya. Karena 0.4 juga menambahkan frame di akhir alih-alih membersihkan konsol, renderer yang melakukan hidrasi dimulai dengan initialClear: false dan mencatat log di bawah shell, lalu tirainya menggeser shell keluar dari tampilan dalam proses penggambaran DevTools yang sama. Konsol dibersihkan tepat satu kali, oleh shell.
✓ Prerendering console shells (5/5) · 1 server-rendered, frame player 56.5 kB (21.3 kB gzip)Shell di-render pada ukuran viewport yang dikonfigurasi, secara default 120 × 36, karena build tidak bisa mengetahui ukuran konsol pengunjung. Dengan viewport.responsive aktif, frame langsung pertama menyesuaikan ukurannya dengan konsol yang ditambatkan. Route dinamis tidak me-render shell, dan ppr: false di text.config.ts menonaktifkan prerender.
Memilih runtime
Runtime klien tetap menjadi default. Penekanan tombol digambar dalam task yang sama, dan aplikasi bisa di-deploy ke hosting statis mana pun. Runtime server cocok untuk dasbor dan tampilan admin yang membaca data privat, serta route dengan dependensi yang tidak Anda inginkan di bundel browser. Satu aplikasi bisa menggabungkan keduanya, dan navigasi di antara keduanya memuat URL tujuan sebagai dokumen baru.
Referensi lengkap ada di Rendering di server.