← بلاگ

⁦console.log⁩ میں React کی رینڈرنگ

⁦Text.js⁩، DevTools کونسول میں React ایپ کو ہر فریم پر ایک اسٹائل شدہ console.log کال کی صورت میں بناتا ہے۔

Adam

⁦Text.js⁩، React ایپس کو ⁦Chrome DevTools⁩ کونسول میں رینڈر کرتا ہے۔ ایک پوشیدہ ان پٹ کے علاوہ، صفحے پر کوئی UI نہیں ہے۔ ایپ کا ہر فریم ایک ہی console.log کال ہے۔

کونسول بطور ڈسپلے

console.log ایک فارمیٹ اسٹرنگ قبول کرتا ہے۔ ہر %c اگلے آرگیومنٹ کی CSS اپنے بعد آنے والے متن پر اگلے %c تک لاگو کرتا ہے:

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

یہ اسٹائل رنگ، پس منظر، بولڈ، اٹالک اور انڈر لائن مقرر کر سکتے ہیں، اور کونسول کا فونٹ مونو اسپیس ہے (macOS پر Menlo)۔ مونو اسپیس فونٹ اور حروف کے ہر سلسلے میں بدل سکنے والے رنگوں کے ساتھ، کونسول اسٹائل والے کریکٹر سیلز کی گرڈ کے طور پر کام کرتا ہے۔ اس پر بارڈر، پینل، ان پٹ اور چارٹ سب بنائے جا سکتے ہیں۔

فریم، سیلز کی ایک گرڈ

رینڈرر ہر فریم کو ایک CellBuffer میں رکھتا ہے۔ حروف ایک ٹائپڈ ایرے میں، متن اور پس منظر کے رنگ دو مزید ایریز میں، اور بولڈ اور انڈر لائن جیسی خصوصیات چوتھے ایرے میں ہوتی ہیں۔ کسی مقررہ سائز کے لیے ایریز ایک بار مختص ہوتی ہیں اور ہر فریم کے لیے دوبارہ استعمال ہوتی ہیں۔

فریم لاگ کرنے کے لیے، ڈرائیور ہر قطار سے گزرتا ہے اور ایک ہی اسٹائل والے پڑوسی سیلز کو سلسلوں میں گروپ کرتا ہے۔ ہر سلسلہ ایک %c span بنتا ہے، اور قطاریں \n سے جوڑی جاتی ہیں۔ ہمارا ⁦100×32⁩ کا ٹیسٹ ڈیش بورڈ، جس میں 3,200 سیل ہیں، تقریباً ⁦200 spans⁩ میں انکوڈ ہوتا ہے۔

ہر فریم کے لیے ایک کال

ہر قطار کو الگ پیغام کے طور پر لاگ کرنا کام نہیں کرتا۔ DevTools میں ہر پیغام کا اپنا بارڈر اور سورس لنک ہوتا ہے، اور DevTools مسلسل آنے والے یکساں پیغامات کو تکرار کے کاؤنٹر کے پیچھے سمیٹ دیتا ہے، اس لیے ٹیبل کی دو یکساں قطاریں ایک میں مل جائیں گی۔ ایک ہی پیغام کے طور پر لاگ ہونے والا فریم یکجا رہتا ہے۔

متن میں پہلے دو چیزوں کو ایسکیپ کرنا ضروری ہے۔ اصل % کو %% لکھتے ہیں، تاکہ 100% جیسا متن اسٹائل آرگیومنٹ استعمال نہ کر سکے۔ DevTools، URLs کو لنکس میں بدل کر اپنے رنگوں میں دوبارہ پینٹ بھی کرتا ہے، اس لیے :// اور www. میں ایک ⁦word joiner⁩ (⁦U+2060⁩) شامل ہوتا ہے، جس کی کوئی چوڑائی نہیں ہوتی:

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;}

غیر فعال فریموں میں کوئی لاگ نہیں

بفر کی ہر قطار کا ہیش بنتا ہے۔ اگر پچھلے فریم کے بعد کوئی ہیش نہ بدلا ہو، تو ڈرائیور اسٹرنگ بنانے سے پہلے واپس آ جاتا ہے اور کونسول کو بالکل نہیں چھیڑتا۔ ان پٹ کا انتظار کرنے والی ایپ کوئی کال نہیں کرتی۔

جب کوئی قطار بدلتی ہے، تو ڈرائیور کونسول صاف کرتا ہے اور نیا فریم لاگ کرتا ہے:

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

صرف وہ قطاریں دوبارہ انکوڈ ہوتی ہیں جن کا ہیش بدلا ہو۔ باقی قطاریں پچھلے فریم کے spans دوبارہ استعمال کرتی ہیں۔

ان پٹ

کونسول کو کی اسٹروکس موصول نہیں ہوتے، اس لیے صفحہ انہیں جمع کرتا ہے۔ ایک پوشیدہ <textarea> کلید دبانے، پیسٹ کرنے اور IME کمپوزیشن کو لے کر ایپ کے لیے کلیدی ایونٹس میں بدلتا ہے۔ صفحے پر کلک کرنے سے اسے فوکس ملتا ہے۔

آگے

⁦npm⁩ پر @textjs/core کے ⁦0.0.x⁩ پروٹوٹائپس سب کچھ ایک ہی پیکیج میں رکھتے ہیں۔ ⁦Text.js 0.1⁩ یہاں بیان کردہ رینڈرر کو @textjs/core میں، React ریکنسائلر کو @textjs/react میں منتقل کرتا ہے، اور ایک ⁦App Router⁩ شامل کرتا ہے۔