DEV Community

Cover image for Pretext.js: 15KB Boyutuyla Metin Düzenini 500 Kat Hızlandıran Kütüphane
Tobias Hoffmann
Tobias Hoffmann

Posted on • Originally published at apidog.com

Pretext.js: 15KB Boyutuyla Metin Düzenini 500 Kat Hızlandıran Kütüphane

Kısaca

Pretext.js, DOM işlemleri yerine saf aritmetik kullanarak çok satırlı metni ölçen ve konumlandıran, sıfır bağımlılıklı bir TypeScript kütüphanesidir. Zorunlu senkron yeniden akışları ortadan kaldırır, getBoundingClientRect()'tan yaklaşık 500 kat daha hızlı metin ölçümü sağlar ve tüm büyük yazı sistemlerini destekler. Sanal kaydırıcılar, sohbet arayüzleri veya veri ızgaraları geliştiriyorsanız, bu kütüphane tarayıcıların 30 yıldır göz ardı ettiği bir sorunu çözer.

Apidog'u bugün deneyin

Giriş

JavaScript'iniz her getBoundingClientRect() çağırdığında veya offsetHeight okuduğunda, tarayıcı tüm işlemleri durdurur. Bekleyen stil değişikliklerini temizler, düzeni yeniden hesaplar ve tam bir render geçişi zorlar. Bu zorunlu senkron yeniden akış, tarayıcıda en maliyetli işlemlerden biridir.

Bunu sanal bir listede 1.000 sohbet balonu veya bir veri ızgarasında 10.000 satır ile çarptığınızda sonuç: Düşen kareler, takılmalar ve kullanıcı deneyiminde bozulmalar.

💡 Apidog ekipleri API odaklı ön uçlar geliştirirken bu sorunu iyi bilir; düzen motorunuz her adımda size karşı savaşırken, yanıt verilerini dinamik arayüzlere sorunsuz bir şekilde aktarmak sürekli bir mücadeledir.

react-motion'ın (21.700+ GitHub yıldızı) geliştiricisi ve Meta/ReasonML'in temel katkıcılarından Cheng Lou, bu sorunu çözmek için Pretext.js'i geliştirdi. Kütüphane Mart 2026'da yayınlandı, birkaç gün içinde 14.000'den fazla GitHub yıldızına ulaştı ve yılın en büyük Hacker News konularından biri oldu.

Bu makalede Pretext.js'in temel çalışma şekli, nasıl uygulandığı ve teknik sınırlamaları pratik uygulama adımları ve kod örnekleriyle ele alınmaktadır.


Pretext.js Nedir?

Pretext.js, saf JavaScript/TypeScript ile çok satırlı metni DOM olmadan ölçen ve konumlandıran bir motordur. DOM ölçümü veya yeniden akış yok; sadece aritmetik.

image-272.png

Ana fikir: Tarayıcıya “bu metin ne kadar yüksek?” diye sormak yerine Canvas API'den alınan font ölçülerini kullanıp matematiksel olarak hesaplama yapmak.

Pretext.js API'sinin Uygulamalı Kullanımı

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

// 1. Metni hazırlayın (bir kez, önbelleğe alınabilir)
const handle = prepare('Hello, pretext.js', '16px "Inter"');

// 2. Herhangi bir genişlikte düzeni hesaplayın
const { height, lineCount } = layout(handle, 400, 24);
Enter fullscreen mode Exit fullscreen mode

İki fonksiyon. prepare() metni ölçüp önbelleğe alır. Sadece bir kez Canvas'a erişir. Ardından layout() fonksiyonu, saf matematikle yüksekliği ve satır sayısını döndürür.


API Yoğun Uygulamalarda Neden Önemli?

Akış API yanıtlarını kullanan uygulamalarda (AI asistanları, gerçek zamanlı dashboardlar, işbirlikçi editörler vb.) gelen metnin yüksekliği DOM'a dokunmadan bilinmelidir. Pretext.js bu ölçümü mikrosaniyeler içinde sunar ve sanal kaydırıcı veya sohbet arayüzlerinde takılmayı engeller.


Pretext.js'in Çözdüğü Temel Sorun

Zorunlu Senkron Yeniden Akışın Maliyeti

Aşağıdaki kodda olduğu gibi:

const elements = document.querySelectorAll('.text-block');
elements.forEach(el => {
  const height = el.getBoundingClientRect().height; // REFLOW!
  // kullan...
});
Enter fullscreen mode Exit fullscreen mode

Her getBoundingClientRect() çağrısı:

  1. JavaScript yürütmeyi durdurur
  2. Tüm stil değişikliklerini temizler
  3. Belge veya alt ağaç için düzeni hesaplar
  4. Değeri döndürür

1.000 öğe için 1.000 tam düzen yeniden hesaplama olur (~94ms, 6 kare düşüşü).

Sanal Kaydırma ve Değişken Yüksekliğin Kabusu

Standart çözüm, öğeleri ekran dışında render edip ölçmek. Ancak bu, DOM'a fazla yük bindirir ve amaçlanan performansı sağlamaz. Pretext.js ile DOM oluşmadan yükseklikler hesaplanır.

Gerçek Performans Sayıları

Yaklaşım 1.000 metin bloğu 500 metin bloğu
DOM (getBoundingClientRect) ~94ms (6 kare) ~47ms
Pretext.js (layout()) ~2ms ~0.09ms
Hız farkı ~47 kat daha hızlı ~500 kat daha hızlı

Pretext.js Nasıl Çalışır? (Kaputun Altında)

1. Aşama: Metin Segmentasyonu

prepare() fonksiyonu, metni Unicode satır sonu kurallarıyla böler. Çok dilli destek:

  • CJK karakterleri (Çince, Japonca, Korece)
  • Arapça ve İbranice (sağdan sola, çift yönlü)
  • Tayca (kelime arası boşluk yok)
  • Hintçe/Devanagari (ligatürler)
  • Emoji (çok kod noktası)
  • Yumuşak kısa çizgiler (­)

2. Aşama: Canvas Ölçümü

Segmentler, Canvas measureText() ile ölçülür.

const ctx = offscreenCanvas.getContext('2d');
ctx.font = '16px "Inter"';
const metrics = ctx.measureText('Hello');
const width = metrics.width;
Enter fullscreen mode Exit fullscreen mode

Aynı metin ve font kombinasyonunda ölçümler önbellekten alınır.

3. Aşama: Saf Aritmetik Düzen

layout() fonksiyonu segment genişliklerini toplar, satır sonlarını belirler ve toplam yüksekliği hesaplar. DOM yok, Canvas yok, sadece toplama ve karşılaştırma.

Yeniden Kullanılabilir İşleyici

Bir kez prepare(), istediğiniz kadar farklı genişlikte layout():

const handle = prepare(longArticleText, '16px "Inter"');
const mobile = layout(handle, 375, 24);
const tablet = layout(handle, 768, 24);
const desktop = layout(handle, 1200, 24);
Enter fullscreen mode Exit fullscreen mode

Pratik Kullanım Durumları

1. Değişken Yükseklikte Metinle Sanal Kaydırma

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 }; // padding dahil
  });
}

const heights = computeHeights(chatMessages, 600); // 10.000 öğe ~4ms
Enter fullscreen mode Exit fullscreen mode

DOM'a dokunmadan doğru yükseklikler.

2. Yapay Zeka Sohbet Arayüzleri

Her yeni token sonrası DOM ölçümü yerine Pretext.js ile yükseklik anında hesaplanır:

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);
  scroller.updateItemHeight(messageId, height + padding);
});
Enter fullscreen mode Exit fullscreen mode

3. Metin Sütunlu Veri Izgaraları

function computeColumnWidth(values: string[], font: string, padding: number) {
  let maxWidth = 0;
  for (const value of values) {
    const handle = prepare(value, font);
    // Tek satır genişliğini almak için sonsuz genişlik
    const { height } = layout(handle, Infinity, 20);
    // handle'ın iç width bilgisini kullanın
    maxWidth = Math.max(maxWidth, /* width hesaplaması */);
  }
  return maxWidth + padding;
}
Enter fullscreen mode Exit fullscreen mode

4. Çok Dilli İçerik Akışları

const posts = [
  { text: 'This library changed everything', lang: 'en' },
  { text: 'RTL text with correct bidirectional layout', lang: 'ar' },
  { text: 'CJK text gets proper character-level breaks', lang: 'zh' },
];

posts.forEach(post => {
  const handle = prepare(post.text, '16px system-ui');
  const { height } = layout(handle, 400, 24);
});
Enter fullscreen mode Exit fullscreen mode

Apidog ile Metin Düzeninizi Test Etme

API destekli metin yoğun arayüzler geliştirirken sadece düzen değil, veri katmanınızın da güvenilir olması gerekir.

image-273.png

Apidog ile Pretext.js entegrasyonlarınızı test edin. Farklı metin uzunlukları, diller ve Unicode uç durumlarını API yanıtlarında simüle edin; sanal kaydırıcınızın doğru çalıştığını doğrulayın.

Yapay zeka sohbet ürünleri geliştiren ekipler için Apidog ile:

  • Parçalı metinle akış yanıtlarını taklit edin
  • Çok dilli yüklerle testler oluşturun
  • Yanıt şemalarını doğrulayın
  • Otomatik test paketleri ile uç durumları kapsayın

Ne kadar hızlı ölçüm yaparsanız yapın, API verisi bozuksa düzen de bozuk olur.


Bilinen Sınırlamalar ve Eleştiriler

Render Doğruluğu Uç Durumlar

Bazı yazı tiplerinde veya tarayıcılarda metin kutu dışına taşabilir. Özellikle şunlarda sorun yaşanabilir:

  • Alışılmadık karakter aralığı
  • Karışık font boyutları
  • Canvas ve DOM alt piksel farklılıkları
  • Tarayıcıya özgü şekillendirme farkları

Sanal kaydırma için çoğu durumda bu hatalar görünmezdir, ancak piksel mükemmel dizgi için DOM ölçümü daha güvenilirdir.

Canvas Ölçümü Tamamen Ücretsiz Değil

prepare() çağrısı Canvas'a erişir. Binlerce benzersiz metin için çok sık çağırırsanız darboğaz olabilir. Önbellekleme ve toplu işlem önerilir.

CSS Özellikleri Desteği Yok

Pretext.js sadece font belirtimiyle ölçüm yapar. letter-spacing, word-spacing, text-indent, text-transform gibi CSS özellikleri hesaba katılmaz.

DOM Render Etmeyi Değiştirmez

Pretext.js yalnızca ölçüm yapar, metni render etmez. Render için yine DOM veya Canvas/SVG gereklidir.


Pretext.js vs. Geleneksel Yaklaşımlar

Özellik Pretext.js DOM ölçümü Tahmini yükseklikler
Hız (1K öğe) ~2ms ~94ms ~0ms
Doğruluk Yüksek (Canvas) Mükemmel Düşük
DOM bağımlılığı prepare() sonrası yok Tam Yok
Yeniden akış tetikleyici Sıfır Bir Sıfır
Çok Dilli Tam Unicode Tam Zayıf
CSS özelliği desteği Sınırlı (font) Tam Yok
Bellek yükü Önbellekli segmentler DOM düğümleri Minimal
Duyarlı düzenler Bir prepare(), çok layout() Genişlik başına yeniden ölç Genişlik başına yeniden tahmin

Kısıtlamalarınıza göre seçim yapın. Piksel mükemmelliği ve CSS özelliği gerekiyorsa DOM ölçümü, performans ve ölçek gerekiyorsa Pretext.js tercih edin.


Başlarken

Kurulum

npm install @chenglou/pretext
# veya
pnpm add @chenglou/pretext
# veya
bun add @chenglou/pretext
Enter fullscreen mode Exit fullscreen mode

Temel Kullanım

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

// Paragraf ölçümü
const handle = prepare(
  'Pretext.js computes text layout without touching the DOM.',
  '16px "Inter"'
);

// Belirli genişlikte yüksekliği al
const result = layout(handle, 600, 24);
console.log(result.height);    // Örneğin: 48 (2 satır x 24px)
console.log(result.lineCount); // Örneğin: 2
Enter fullscreen mode Exit fullscreen mode

React ile Entegrasyon

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>
  );
}
Enter fullscreen mode Exit fullscreen mode

Herhangi bir mesaj DOM'a render edilmeden önce doğru yükseklik ile sanal sohbet listesi.

Etkileşimli Oyun Alanı

Pretext.js web sitesinde pretextjs.dev/playground adresinde metin yapıştırıp font seçip düzeni gerçek zamanlı görebilirsiniz. Entegrasyondan önce davranışı test edin.


Pretext.js'i Ne Zaman Kullanmamalısınız?

  • Statik içerikli sayfalarda: Metin değişmiyorsa ve sanallaştırma yoksa Pretext.js'e gerek yok.
  • Piksel mükemmel baskı dizgisi: Alt piksel farklılıklar önemliyse DOM ölçümü kullanın.
  • Yoğun CSS metin stilleri: CSS özellikleriyle uyumlu ölçüm gerekirse DOM daha doğru.
  • Sunucu tarafı render: Canvas API olmadan çalışmaz; SSR için henüz destek yok.
  • Küçük, statik listeler: <50 öğe için DOM ölçümü yeterince hızlıdır.

Sıkça Sorulan Sorular

Pretext.js Üretim İçin Hazır mı?

Mart 2026'da yayınlandı, 14.000+ GitHub yıldızı aldı. Yaratıcısı Cheng Lou, milyonlarca kullanıcıya sahip Midjourney'nin ön ucunu yönetiyor. Test paketi onlarca dil ve uç durumu kapsıyor. Yine de yeni bir kütüphane; yazı tipinize ve içeriğinize göre test edin ve sürümünüzü sabitleyin.

Pretext.js React, Vue, Svelte ile Uyumlu mu?

Evet. Çerçeve bağımsızdır. prepare() ve layout() fonksiyonlarını React hook'larında, Vue composable'larında, Svelte store'larında veya düz JavaScript'te kullanabilirsiniz.

Web Fontlar Nasıl İşlenir?

prepare() çağrısı sırasında kullanılan fontun tarayıcıda yüklü olması gerekir. Yüklenmediyse yedek font ile ölçer ve yanlış sonuç verebilir. Ölçüm öncesi fontun yüklü olduğundan emin olmak için document.fonts.ready kullanın.

Canvas veya SVG Render İçin Kullanabilir miyim?

Evet. Pretext.js render hedefinden bağımsız ölçüm yapar. Satır sonları ve yükseklikleri ile Canvas 2D, WebGL, SVG veya DOM'da konumlandırma yapabilirsiniz.

RTL (Sağdan Sola) Dilleri Destekliyor mu?

Evet. Arapça, İbranice ve diğer RTL dillerde çift yönlü metin desteği ile doğru ölçüm sağlar.

Paket Boyutu Nedir?

Sıfır bağımlılıkla 15KB küçültülmüş. Sadece standart tarayıcı API'leri (Canvas measureText(), Intl.Segmenter) kullanılır.

DOM Ölçümüyle Doğruluk Karşılaştırması

Çoğu içerikte 1-2 piksel içinde eşleşir. letter-spacing, word-spacing gibi CSS özellikleri hesaba katılmaz; bu özelliklerde fark daha büyük olabilir.

Stilize Edilmiş Metinleri Ölçebilir mi?

Her prepare() çağrısı tek bir font ile çalışır. Karışık stiller için metni segmentlere ayırıp her stil için ayrı işleyici oluşturun.


Sonuç

Pretext.js, DOM yeniden akışı olmadan hızlı ve doğru metin ölçümü sunar. Sanal kaydırıcılar, sohbet arayüzleri, veri ızgaraları veya binlerce metin bloğunu ölçmesi gereken her arayüz için iki fonksiyon çağrısıyla büyük performans farkı sağlar.

Kütüphane CSS metin özelliklerini tam desteklemez, alt piksel farklılıklar olabilir ve henüz sunucu tarafı desteği yoktur. Ancak büyük, dinamik ve çok dilli metin listelerinde sanal kaydırma hızında rakipsizdir.

Daha hızlı metin yoğun arayüzler oluşturmaya hazır mısınız? Veri katmanınızı Apidog ile test edin, ardından Pretext.js'i render hattınıza entegre edin.

Top comments (0)