Pretext.js: Library 15KB yang Membuat Tata Letak Teks 500x Lebih Cepat

Ashley Innocent

Ashley Innocent

31 March 2026

Pretext.js: Library 15KB yang Membuat Tata Letak Teks 500x Lebih Cepat

Apidog untuk Perusahaan

Penerapan On-Premises

SSO & RBAC

Sesuai SOC 2

Jelajahi Apidog Enterprise

Singkatnya

Pretext.js adalah pustaka TypeScript tanpa dependensi yang mengukur dan memposisikan teks multi-baris melalui aritmatika murni alih-alih operasi DOM. Ini menghilangkan reflow sinkron paksa, memberikan pengukuran teks ~500x lebih cepat daripada getBoundingClientRect(), dan mendukung setiap sistem penulisan utama di planet ini. Jika Anda membangun scroller virtual, UI obrolan, atau data grid, pustaka ini memecahkan masalah yang telah diabaikan browser selama 30 tahun.

Pendahuluan

Setiap kali JavaScript Anda memanggil getBoundingClientRect() atau membaca offsetHeight, browser menghentikan segalanya. Ini menghapus perubahan gaya yang tertunda, menghitung ulang tata letak, dan memaksa proses rendering penuh. Ini disebut reflow sinkron paksa, dan ini adalah satu-satunya operasi paling mahal yang dapat dilakukan browser.

Sekarang kalikan itu dengan 1.000 gelembung obrolan dalam daftar virtual. Atau 10.000 baris dalam data grid. Hasilnya? Bingkai yang terputus, jank, dan pengguna yang mengira aplikasi Anda rusak.

💡
Apidog tim yang membangun frontend berbasis API sangat memahami kesulitan ini; mengalirkan data respons ke dalam UI dinamis sambil menjaga semuanya tetap mulus adalah perjuangan konstan ketika mesin tata letak Anda melawan Anda di setiap langkah.
button

Cheng Lou, pengembang di balik react-motion (21.700+ bintang GitHub) dan kontributor utama React dan ReasonML di Meta, membangun Pretext.js untuk memperbaiki masalah ini. Pustaka ini dirilis pada Maret 2026, mencapai 14.000+ bintang GitHub dalam hitungan hari, dan memicu salah satu utas Hacker News terbesar tahun ini.

Artikel ini menguraikan apa yang dilakukan Pretext.js, bagaimana cara kerjanya di balik layar, kapan Anda harus menggunakannya, dan kekurangannya. Anda akan pulang dengan mengetahui apakah pustaka ini cocok untuk tumpukan teknologi Anda.

Apa itu Pretext.js?

Pretext.js adalah mesin tata letak teks JavaScript/TypeScript murni. Ini mengukur dan memposisikan teks multi-baris sepenuhnya melalui aritmatika; tanpa getBoundingClientRect(), tanpa offsetHeight, tanpa reflow, tanpa thrashing.

Ide intinya sederhana. Daripada bertanya kepada browser "berapa tinggi teks ini?" (yang memaksa browser untuk merendernya terlebih dahulu), Pretext.js menghitung jawabannya secara matematis menggunakan metrik font dari Canvas API.

Berikut adalah seluruh API:

import { prepare, layout } from '@chenglou/pretext';

// Langkah 1: Siapkan teks (sekali, dapat di-cache)
const handle = prepare('Halo, pretext.js', '16px "Inter"');

// Langkah 2: Tata letak pada lebar berapa pun (aritmatika murni, mikrodetik)
const { height, lineCount } = layout(handle, 400, 24);

Itu saja. Dua fungsi. Satu mengukur segmen teks dan menyimpannya dalam cache. Yang lain melakukan aritmatika untuk menghitung tata letak. Panggilan prepare() adalah satu-satunya operasi yang menyentuh browser (melalui Canvas measureText()). Setelah itu, layout() adalah matematika murni.

Mengapa ini penting untuk aplikasi yang banyak menggunakan API

Jika Anda membangun aplikasi yang mengonsumsi respons API streaming; bayangkan asisten AI, dasbor real-time, atau editor kolaboratif; Anda perlu mengetahui tinggi teks yang masuk sebelum Anda merendernya. Tanpa itu, scroller virtual Anda akan tersendat, UI obrolan Anda melompat, dan pengguna Anda akan menyadarinya.

Pretext.js memberi Anda tinggi tersebut dalam mikrodetik, bukan milidetik. Perbedaan ini akan bertambah cepat.

Masalah yang dipecahkan Pretext.js

Untuk memahami mengapa pustaka ini ada, Anda perlu memahami apa yang terjadi ketika JavaScript membaca properti tata letak.

Penjelasan reflow sinkron paksa

Saat Anda menulis kode ini:

const elements = document.querySelectorAll('.text-block');
elements.forEach(el => {
  const height = el.getBoundingClientRect().height; // REFLOW!
  // gunakan tinggi untuk penempatan...
});

Setiap panggilan getBoundingClientRect() memaksa browser untuk:

  1. Menjeda eksekusi JavaScript
  2. Menghapus semua perubahan gaya yang tertunda
  3. Menghitung ulang tata letak untuk seluruh dokumen (atau sub-pohon)
  4. Mengembalikan nilai yang dihitung

Ini disebut "layout thrashing." Dalam loop yang mengukur 1.000 elemen, browser melakukan 1.000 perhitungan ulang tata letak penuh. Biayanya? Kira-kira 94 milidetik, yang berarti 6 bingkai hilang pada 60fps.

Masalah pengguliran virtual

Pustaka pengguliran virtual (seperti react-window atau tanstack-virtual) perlu mengetahui tinggi setiap item untuk menghitung posisi pengguliran. Untuk item dengan tinggi tetap, ini sepele. Untuk konten teks dengan tinggi variabel, itu adalah mimpi buruk.

Solusi standarnya adalah merender item di luar layar, mengukurnya, lalu memposisikannya. Ini berhasil tetapi mengalahkan tujuan pengguliran virtual; Anda merender node DOM yang ingin Anda hindari untuk dirender.

Beberapa pustaka memperkirakan tinggi dan memperbaikinya setelah render, menyebabkan lompatan yang terlihat. Yang lain memaksa pengembang untuk menentukan tinggi tetap, membatasi apa yang dapat Anda tampilkan.

Pretext.js menghilangkan seluruh kategori solusi ini. Anda menghitung tinggi teks yang tepat sebelum node DOM apa pun ada.

Angka nyata

Pretext.js menerbitkan hasil benchmark di situs mereka:

Pendekatan 1.000 blok teks 500 blok teks
DOM (getBoundingClientRect) ~94ms (6 bingkai hilang) ~47ms
Pretext.js (layout()) ~2ms ~0.09ms
Perbedaan kecepatan ~47x lebih cepat ~500x lebih cepat

Peningkatan kecepatan lebih dramatis dengan batch yang lebih kecil karena overhead per panggilan dari pengukuran DOM tetap konstan sementara biaya aritmatika Pretext meningkat secara linear.

Bagaimana Pretext.js bekerja di balik layar

Pustaka ini beroperasi dalam tiga fase yang berbeda. Memahami ini membantu Anda mengoptimalkan cara Anda menggunakannya.

Fase 1: Segmentasi teks

Saat Anda memanggil prepare(), Pretext.js pertama-tama menormalisasi teks input Anda. Ini menangani spasi kosong, menerapkan aturan pemisah baris Unicode (UAX #14), dan membagi teks menjadi unit yang dapat dipisah.

Di sinilah dukungan multibahasa berperan. Mesin segmentasi menangani dengan benar:

Fase 2: Pengukuran Canvas

Setelah segmentasi, Pretext.js memasukkan setiap segmen melalui Canvas measureText() API. Ini adalah satu-satunya panggilan browser yang dibuat pustaka, dan cepat karena pengukuran teks Canvas tidak memicu reflow tata letak.

// Internal: bagaimana Pretext mengukur teks
const ctx = offscreenCanvas.getContext('2d');
ctx.font = '16px "Inter"';
const metrics = ctx.measureText('Halo'); // Tidak ada reflow!
const width = metrics.width; // Lebar maju glyph

Pengukuran di-cache berdasarkan segmen dan kombinasi font. Jika Anda memanggil prepare() dengan teks dan font yang sama dua kali, panggilan kedua akan menggunakan kembali data yang di-cache.

Fase 3: Tata letak aritmatika murni

Fungsi layout() mengambil lebar segmen yang di-cache dan lebar wadah, lalu menghitung pemisah baris menggunakan algoritma serakah:

  1. Jumlahkan lebar segmen hingga totalnya melebihi lebar wadah
  2. Pindah ke baris baru
  3. Ulangi hingga semua segmen ditempatkan
  4. Kalikan jumlah baris dengan tinggi baris untuk mendapatkan tinggi total

Tidak ada DOM. Tidak ada Canvas. Penjumlahan dan perbandingan murni.

Inilah mengapa layout() sangat cepat; ia melakukan perhitungan yang sama seperti yang akan Anda tulis di atas kertas dengan penggaris dan kalkulator.

Pola handle yang dapat digunakan kembali

Salah satu keputusan desain terbaik di Pretext.js adalah bahwa prepare() mengembalikan handle yang dapat digunakan kembali. Satu panggilan prepare() berfungsi di semua lebar wadah:

const handle = prepare(longArticleText, '16px "Inter"');

// Hitung tinggi untuk seluler, tablet, dan desktop dalam mikrodetik
const mobile = layout(handle, 375, 24);   // { height: 2400, lineCount: 100 }
const tablet = layout(handle, 768, 24);   // { height: 1200, lineCount: 50 }
const desktop = layout(handle, 1200, 24); // { height: 720, lineCount: 30 }

Pola ini sempurna untuk perhitungan desain responsif. Anda mengukur sekali dan menata letak pada lebar apa pun secara instan.

Kasus penggunaan praktis

1. Pengguliran virtual dengan teks tinggi variabel

Ini adalah kasus penggunaan utama. Berikut cara Anda mengintegrasikan Pretext.js dengan scroller virtual:

import { prepare, layout } from '@chenglou/pretext';

interface TextItem {
  id: string;
  content: string;
}

function computeHeights(items: TextItem[], containerWidth: number) {
  return items.map(item => {
    const handle = prepare(item.content, '14px "Inter"');
    const { height } = layout(handle, containerWidth, 20);
    return { id: item.id, height: height + 32 }; // +32 untuk padding
  });
}

// 10.000 item diukur dalam ~4ms
const heights = computeHeights(chatMessages, 600);

Tidak ada rendering di luar layar. Tidak ada estimasi tinggi. Tidak ada lompatan yang terlihat saat item bergulir ke tampilan.

2. Antarmuka obrolan AI

Asisten AI mengalirkan respons token demi token. Setiap token baru dapat mengubah jumlah baris, menggeser semua yang ada di bawahnya. Dengan pengukuran DOM tradisional, setiap pembaruan token memicu reflow.

Dengan Pretext.js, Anda menghitung ulang tinggi setelah setiap bagian tiba tanpa menyentuh DOM:

let streamedText = '';
const font = '15px "SF Pro"';

socket.on('token', (token: string) => {
  streamedText += token;
  const handle = prepare(streamedText, font);
  const { height } = layout(handle, bubbleWidth, 22);
  
  // Perbarui posisi scroller virtual tanpa pengukuran DOM
  scroller.updateItemHeight(messageId, height + padding);
});

3. Data grid dengan kolom teks

Aplikasi bergaya spreadsheet memerlukan penyesuaian ukuran kolom otomatis. Mengukur ribuan nilai sel melalui DOM itu mahal. Pretext.js membuatnya cepat:

function computeColumnWidth(values: string[], font: string, padding: number) {
  let maxWidth = 0;
  for (const value of values) {
    const handle = prepare(value, font);
    // Tata letak dengan lebar tak terbatas = satu baris = lebar teks alami
    const { height } = layout(handle, Infinity, 20);
    // Gunakan pelacakan lebar internal handle untuk ukuran kolom
    maxWidth = Math.max(maxWidth, /* lebar yang dihitung */);
  }
  return maxWidth + padding;
}

4. Umpan konten multibahasa

Umpan media sosial dengan konten skrip campuran (postingan Tiongkok diikuti oleh balasan Arab diikuti oleh komentar Korea) sangat sulit untuk divirtualisasikan karena setiap skrip memiliki aturan pemisah baris yang berbeda.

Pretext.js menangani semuanya dengan API yang sama:

const posts = [
  { text: 'Pustaka ini mengubah segalanya', lang: 'en' },
  { text: 'Teks RTL dengan tata letak dua arah yang benar', lang: 'ar' },
  { text: 'Teks CJK mendapatkan pemisah tingkat karakter yang tepat', lang: 'zh' },
];

// API yang sama, hasil yang benar untuk setiap skrip
posts.forEach(post => {
  const handle = prepare(post.text, '16px system-ui');
  const { height } = layout(handle, 400, 24);
});

Menguji tata letak teks Anda dengan Apidog

Saat Anda membangun UI yang padat teks yang didukung oleh API, mendapatkan tata letak yang tepat hanyalah separuh perjuangan. Anda juga perlu memverifikasi bahwa respons API yang mengalirkan data ke komponen teks Anda memberikan data yang benar, dalam format yang benar, dan dengan kecepatan yang tepat.

Apidog membuatnya mudah. Anda dapat membuat mock respons API streaming untuk menguji bagaimana integrasi Pretext.js Anda menangani pemuatan teks progresif. Siapkan skenario pengujian dengan panjang teks, bahasa, dan kasus tepi Unicode yang berbeda, lalu verifikasi bahwa scroller virtual Anda berfungsi dengan benar sebelum menyebarkan.

Untuk tim yang membangun produk obrolan AI, lingkungan pengujian API Apidog memungkinkan Anda:

Ini penting karena pustaka tata letak teks hanya sebaik data yang mengalir ke dalamnya. Respons API yang buruk menghasilkan tata letak yang buruk, terlepas dari seberapa cepat mesin pengukuran Anda berjalan.

button

Keterbatasan dan kritik yang diketahui

Pretext.js tidak sempurna. Utas Hacker News memunculkan beberapa kekhawatiran valid yang patut diketahui sebelum Anda mengadopsinya.

Kasus tepi akurasi rendering

Beberapa pengguna melaporkan teks melampaui kotak pembatas dalam demo Safari dan Chrome. Aritmatika pustaka dapat menyimpang dari tata letak asli browser dalam skenario tertentu:

Kasus tepi ini kurang penting untuk pengguliran virtual (di mana beberapa piksel kesalahan tidak terlihat) dan lebih penting untuk tata letak tipografi yang sempurna piksel.

Pengukuran Canvas tidak gratis

Panggilan prepare() masih mengenai mesin teks Canvas browser. Untuk aplikasi yang membuat ribuan handle prepare() unik per bingkai, ini dapat menjadi hambatan. Solusinya adalah caching dan batching, tetapi pustaka tidak memberlakukan keduanya.

Tidak ada dukungan properti CSS

Pretext.js mengukur teks mentah dengan spesifikasi font. Ini tidak memperhitungkan properti CSS yang memengaruhi tata letak:

Jika gaya teks Anda bergantung pada properti CSS ini, tinggi yang dihitung tidak akan cocok dengan apa yang dirender browser. Anda perlu memperhitungkan ini secara manual atau menerima perbedaannya.

Ini tidak menggantikan rendering DOM

Pretext.js memberi tahu Anda seberapa tinggi teks. Itu tidak merender teks untuk Anda. Anda masih memerlukan node DOM (atau rendering Canvas/SVG) untuk menampilkan teks. Nilai pustaka ini ada pada fase pengukuran, bukan fase rendering.

Pretext.js vs. pendekatan tradisional

Fitur Pretext.js Pengukuran DOM Perkiraan tinggi
Kecepatan (1K item) ~2ms ~94ms ~0ms (tidak ada pengukuran)
Akurasi Tinggi (berbasis Canvas) Sempurna (kebenaran dasar) Rendah (heuristik)
Ketergantungan DOM Tidak ada setelah prepare() Penuh Tidak ada
Pemicu reflow Nol Satu per pengukuran Nol
Multibahasa Dukungan Unicode penuh Penuh (bawaan browser) Buruk (rasio hardcode)
Dukungan properti CSS Terbatas (hanya font) Penuh Tidak ada
Overhead memori Segmen yang di-cache Node DOM Minimal
Tata letak responsif Satu prepare(), banyak layout() Ukur ulang per lebar Perkirakan ulang per lebar

Pilihan yang tepat tergantung pada batasan Anda. Jika Anda memerlukan akurasi sempurna piksel dan dukungan properti CSS, pengukuran DOM masih merupakan kebenaran dasar. Jika Anda memerlukan kecepatan di ribuan item dan dapat menoleransi perbedaan sub-piksel kecil, Pretext.js menang dengan selisih yang lebar.

Memulai

Instalasi

npm install @chenglou/pretext
# atau
pnpm add @chenglou/pretext
# atau
bun add @chenglou/pretext

Penggunaan dasar

import { prepare, layout } from '@chenglou/pretext';

// Ukur sebuah paragraf
const handle = prepare(
  'Pretext.js menghitung tata letak teks tanpa menyentuh DOM.',
  '16px "Inter"'
);

// Dapatkan tinggi pada lebar wadah tertentu
const result = layout(handle, 600, 24);
console.log(result.height);    // mis., 48 (2 baris x 24px)
console.log(result.lineCount); // mis., 2

Integrasi dengan React

import { prepare, layout } from '@chenglou/pretext';
import { useVirtualizer } from '@tanstack/react-virtual';
import { useMemo, useRef } from 'react';

function VirtualChat({ messages }: { messages: string[] }) {
  const parentRef = useRef<HTMLDivElement>(null);
  const containerWidth = 600;
  const font = '14px "Inter"';
  const lineHeight = 20;

  const heights = useMemo(() => {
    return messages.map(msg => {
      const handle = prepare(msg, font);
      const { height } = layout(handle, containerWidth, lineHeight);
      return height + 24; // padding
    });
  }, [messages]);

  const virtualizer = useVirtualizer({
    count: messages.length,
    getScrollElement: () => parentRef.current,
    estimateSize: (index) => heights[index],
  });

  return (
    <div ref={parentRef} style={{ height: '100vh', overflow: 'auto' }}>
      <div style={{ height: virtualizer.getTotalSize(), position: 'relative' }}>
        {virtualizer.getVirtualItems().map(virtualRow => (
          <div
            key={virtualRow.key}
            style={{
              position: 'absolute',
              top: virtualRow.start,
              width: containerWidth,
            }}
          >
            {messages[virtualRow.index]}
          </div>
        ))}
      </div>
    </div>
  );
}

Ini memberi Anda obrolan virtual dengan tinggi item yang akurat yang dihitung sebelum pesan apa pun dirender ke DOM. Tidak ada estimasi, tidak ada koreksi lompatan, tidak ada reflow.

Arena bermain interaktif

Situs web Pretext.js menyertakan arena bermain interaktif di pretextjs.dev/playground tempat Anda dapat menempelkan teks, memilih font, menyesuaikan lebar wadah, dan melihat perhitungan tata letak secara real time. Ini adalah cara tercepat untuk memverifikasi perilaku sebelum mengintegrasikan.

Kapan Anda TIDAK boleh menggunakan Pretext.js

Pretext.js bukanlah alat yang tepat untuk setiap masalah pengukuran teks:

FAQ

Apakah Pretext.js siap produksi?

Pustaka ini dirilis pada Maret 2026 dan mendapatkan 14.000+ bintang GitHub dalam hitungan hari. Cheng Lou, penciptanya, mengelola frontend Midjourney; sebuah sistem produksi yang melayani jutaan pengguna. Suite pengujian pustaka ini mencakup puluhan bahasa dan kasus tepi. Meskipun demikian, ini adalah rilis baru. Sematkan versi Anda dan uji terhadap font dan konten spesifik Anda.

Apakah Pretext.js berfungsi dengan React, Vue, dan Svelte?

Ya. Pretext.js agnostik terhadap framework. Ini adalah pustaka TypeScript murni dengan dua fungsi. Anda memanggil prepare() dan layout() di mana pun Anda membutuhkan pengukuran teks; di dalam React hooks, Vue composables, Svelte stores, atau JavaScript biasa.

Bagaimana Pretext.js menangani font web?

Fungsi prepare() mengukur teks menggunakan font apa pun yang telah dimuat browser pada saat pemanggilan. Jika font web Anda belum dimuat, pengukuran akan menggunakan font fallback dan menghasilkan hasil yang salah. Pastikan font Anda dimuat sebelum memanggil prepare(). Gunakan Font Loading API (document.fonts.ready) untuk memverifikasi.

Bisakah saya menggunakan Pretext.js untuk rendering Canvas atau SVG?

Ya. Pustaka ini menghitung tata letak teks yang agnostik terhadap target rendering. Anda dapat menggunakan tinggi dan pemisah baris yang dihitung untuk memposisikan teks di Canvas 2D, WebGL, SVG, atau DOM. Situs web Pretext.js menunjukkan contoh semua target rendering ini.

Apakah ini mendukung bahasa RTL (kanan-ke-kiri)?

Ya. Pretext.js menangani skrip Arab, Ibrani, dan RTL lainnya dengan dukungan teks dua arah yang tepat. Ini juga menangani teks arah campuran (misalnya, teks Arab dengan kata-kata Inggris yang tertanam) dengan benar.

Berapa ukuran bundelnya?

15KB diperkecil dengan nol dependensi. Tidak diperlukan polyfill. Pustaka ini hanya menggunakan API browser standar (Canvas measureText() dan Intl.Segmenter jika tersedia).

Seberapa akurat dibandingkan dengan pengukuran DOM?

Untuk sebagian besar konten teks, Pretext.js cocok dengan tata letak DOM dalam 1-2 piksel. Akurasi bergantung pada font dan properti CSS yang Anda gunakan. Properti seperti letter-spacing dan word-spacing tidak diperhitungkan, jadi jika Anda menggunakannya, harapkan perbedaan yang lebih besar. Untuk pengguliran virtual, di mana beberapa piksel kesalahan tidak terlihat, akurasi lebih dari cukup.

Bisakah Pretext.js mengukur teks bergaya (tebal, miring, ukuran campuran)?

Setiap panggilan prepare() mengambil satu spesifikasi font. Untuk teks dengan gaya campuran (kata-kata tebal dalam teks biasa), Anda perlu membagi teks sendiri dan membuat handle terpisah untuk setiap gaya. Ini adalah batasan yang diketahui yang mungkin akan ditangani di versi mendatang.

Kesimpulan

Pretext.js memecahkan masalah yang telah diabaikan browser selama tiga dekade: pengukuran teks yang cepat, akurat, tanpa reflow DOM. Bagi pengembang yang membangun scroller virtual, UI obrolan, data grid, atau antarmuka apa pun yang perlu mengukur ribuan blok teks, pustaka ini menggantikan seluruh kategori solusi dengan dua panggilan fungsi.

Pustaka ini bukan solusi ajaib. Ini tidak mendukung properti teks CSS di luar spesifikasi font, memiliki perbedaan akurasi sub-piksel kecil, dan belum berfungsi di sisi server. Namun untuk kasus penggunaan targetnya; pra-komputasi tinggi teks untuk daftar virtual; tidak ada yang menandinginya.

Siap membangun UI yang padat teks lebih cepat? Mulailah dengan menguji endpoint API Anda dengan Apidog untuk memastikan lapisan data Anda kokoh, lalu masukkan Pretext.js ke dalam pipeline rendering Anda.

button

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.