← Blog

React’i console.log içinde render etme

Text.js, bir React uygulamasını DevTools konsolunda kare başına tek bir stillendirilmiş console.log çağrısıyla çizer.

Adam

Text.js, React uygulamalarını Chrome DevTools konsolunda render eder. Gizli bir giriş alanı dışında sayfada kullanıcı arayüzü yoktur. Uygulamanın her karesi tek bir console.log çağrısıdır.

Ekran olarak konsol

console.log bir biçim dizesi kabul eder. Her %c, sonraki argümandaki CSS’i kendisinden sonraki metne, bir sonraki %c ifadesine kadar uygular:

console.log("%c▼ Text.js%c ready", "color:#ededed;font-weight:700", "color:#45a557");

Bu stiller renkleri, arka planları, kalınlığı, italik yazımı ve alt çizgiyi ayarlayabilir; konsol yazı tipi ise eş aralıklıdır (macOS’te Menlo). Eş aralıklı yazı tipi ve her karakter grubunda değişebilen renklerle konsol, stillendirilmiş karakter hücrelerinden oluşan bir ızgara işlevi görür. Üzerine kenarlıklar, paneller, giriş alanları ve grafikler çizilebilir.

Hücre ızgarası olarak kare

Render motoru her kareyi bir CellBuffer içinde tutar. Karakterler bir türlenmiş dizide, ön plan ve arka plan renkleri iki ayrı dizide, kalınlık ve alt çizgi gibi nitelikler ise dördüncü bir dizide bulunur. Diziler belirli bir boyut için bir kez ayrılır ve her karede yeniden kullanılır.

Sürücü, bir kareyi günlüğe yazmak için her satırı dolaşır ve aynı stili paylaşan komşu hücreleri gruplar. Her grup bir %c span olur ve satırlar \n ile birleştirilir. 3.200 hücreden oluşan 100×32 boyutundaki test panomuz yaklaşık 200 span olarak kodlanır.

Kare başına bir çağrı

Her satırı ayrı bir mesaj olarak günlüğe yazmak işe yaramaz. DevTools’ta her mesajın kendi kenarlığı ve kaynak bağlantısı olur; ayrıca DevTools art arda gelen aynı mesajları bir tekrar sayacının arkasında toplar, bu yüzden bir tablonun birbirinin aynısı iki satırı tek satırda birleşir. Tek mesaj olarak günlüğe yazılan kare tek parça kalır.

Önce metindeki iki öğeye kaçış uygulanması gerekir. Düz metindeki %, %% olarak yazılır; böylece 100% gibi metinler bir stil argümanını tüketemez. DevTools ayrıca URL’leri bağlantılara dönüştürüp kendi renkleriyle yeniden boyar; bu yüzden :// ve www. içine genişliği olmayan bir word joiner (U+2060) eklenir:

export function escapeConsoleText(text: string, allowLink = false): string {  let s = text;  if (s.includes("%")) s = s.replaceAll("%", "%%");  if (!allowLink) {    if (s.includes(LINK_SCHEME)) s = s.replaceAll(LINK_SCHEME, LINK_SCHEME_SAFE);    if (s.includes(WWW) || s.includes("WWW.")) s = s.replace(/www\./gi, (m) => `${m.slice(0, 3)}\u2060.`);  }  return s;}

Boşta kalan karelerde günlük kaydı yok

Tampondaki her satırın hash değeri hesaplanır. Son kareden bu yana hiçbir hash değeri değişmediyse sürücü bir dize oluşturmadan geri döner ve konsola hiç dokunmaz. Girdi bekleyen bir uygulama hiçbir çağrı yapmaz.

Bir satır değiştiğinde sürücü konsolu temizler ve yeni kareyi günlüğe yazar:

const { frame, dirtyRows } = this.encode(buffer, options);if (frame === null) return SKIPPED;if (this.clearEachFrame) target.clear();target.log(frame.format, ...frame.args);

Yalnızca hash değeri değişen satırlar yeniden kodlanır. Diğerleri önceki karenin span öğelerini yeniden kullanır.

Girdi

Konsol tuş vuruşlarını almaz, bu yüzden bunları sayfa toplar. Gizli bir <textarea>; tuşa basma, yapıştırma ve IME ile metin oluşturma girdilerini alıp uygulama için tuş olaylarına dönüştürür. Sayfaya tıklamak bu alana odaklanır.

Sonraki adım

npm üzerindeki @textjs/core 0.0.x prototipleri her şeyi tek pakette tutar. Text.js 0.1, burada açıklanan render motorunu @textjs/core paketine, React uzlaştırıcısını @textjs/react paketine taşır ve bir App Router ekler.