← المدونة

البنية المعكوسة

كيف يتحول تثبيت تحديث React إلى استدعاء console.log واحد في DevTools.

Adam

في إطار عمل DOM، تتحول المكوّنات إلى عقد DOM يخططها المتصفح ويرسمها في الصفحة. في Text.js، تتحول المكوّنات إلى خلايا، ويتحول كل إطار تغيّرت خلاياه إلى استدعاء واحد للدالة console.log في DevTools. نسمي هذا البنية المعكوسة.

مسار المعالجة

React ─▶ reconciler ─▶ Yoga ─▶ CellBuffer ─▶ row-hash gate ─▶ RLE ─▶ console.log

توجد كل مرحلة لأن وحدة التحكم وسيلة عرض غير معتادة. فهي أحادية المسافة وقائمة على الصفوف، وتُنسّق باستخدام %c، وتقرر DevTools متى تعيد رسمها.

المطابق

الحزمة @textjs/react هي مطابق لمكتبة ⁦React 19⁩ ([email protected]) بعنصرين مضيفين، هما tx-box و tx-text، إضافة إلى مثيلات نصية للعناصر الأبناء من نوع سلسلة نصية. كل ما تستورده، من <Box> إلى <Markdown>، مبني على هذه العناصر. تُجدول عمليات الإيداع باستخدام requestAnimationFrame، وتؤدي ضغطة مفتاح أو عملية لصق إلى عرض متزامن في المهمة نفسها.

التخطيط

تخطط Yoga، المترجمة إلى WebAssembly، الشجرة باستخدام pointScaleFactor = 1، بحيث يقع كل صندوق على خلية كاملة. يُقاس النص باستخدام Intl.Segmenter وجداول عرض محارف شرق آسيا، لذا يشغل 你好 أربع خلايا ويشغل 🚀 خليتين. إذا كان التعديل لا يمكن أن يغيّر حجم عقدة نصية، فلا تُستدعى Yoga مجددًا.

CellBuffer

الإطار شبكة من مصفوفات محددة النوع تُخصّص مرة واحدة: المحارف في Uint32Array، ولونا المقدمة والخلفية بصيغة 0xRRGGBBAA معبأة، والسمات بقناع بتات من نوع Uint16Array. تكتب عملية الرسم في هذه المصفوفات وتتتبع الصفوف التي مستها.

البوابة

لكل صف قيمة تجزئة ⁦FNV-1a⁩ بطول 32 بت مخزنة مؤقتًا. تُعاد تجزئة الصفوف التي كُتب فيها منذ الإطار الأخير فقط. إذا لم يتغير أي صف، يعود برنامج التشغيل قبل بناء سلسلة نصية ولا يجري أي استدعاء لوحدة التحكم. لا يستهلك مؤشر دوران في علامة تبويب مخفية أي موارد لأنه لا يتقدم.

ترميز أطوال التتابعات

تُفحص الصفوف المتغيرة مجددًا لتقسيمها إلى تتابعات متطابقة التنسيق، ويتحول كل تتابع إلى span واحد باستخدام %c. تستمر التتابعات عبر فواصل الأسطر. تُخزّن سلاسل CSS بنسخ مشتركة وراء معرّفات تنسيق صحيحة، لذا لا يبني المسار الساخن السلسلة نفسها مرتين أبدًا. تتكون لوحة معلومات بحجم ⁦100×32⁩ من 3,200 خلية و⁦149 span⁩.

تحمي سلسلة التنسيق أيضًا من سلوكين في DevTools. تُكتب علامة % الحرفية بالشكل %%. يُوضع محرف ⁦word joiner⁩ بعد ://، وداخل www. وفي path:line، حتى لا تحوّل DevTools النص إلى رابط وتعيد رسمه بألوانها الخاصة.

استدعاء واحد

كل إطار متغير هو استدعاء واحد:

console.log("%c\u200b%c\n%c▼ OpenCode Lite%c …", "margin-top:100vh;", "", "color:#fafafa;…", …);

تُلحق الإطارات، وتُضبط وتيرتها لتوافق محدد معدل DevTools البالغ 50 ms، وتُبدّل ضمن عملية رسم واحدة. يتناول مقال Turbolog: إزالة الوميض هذا الجزء.

الإدخال

لا تستطيع وحدة التحكم استقبال ضغطات المفاتيح، لذا تستقبلها الصفحة. يجمع عنصر <textarea> مخفي المفاتيح واللصق وتركيب النص باستخدام IME، وتمرّر أحداث wheel مكوّنات ScrollBox. على textjs.org، تشكل صفحتا Playground و OpenCode لوحة تركيز كبيرة واحدة. افتح وحدة التحكم، ثم انقر الصفحة للكتابة.

ما تراه الصفحة

لا تستطيع الصفحة قراءة حجم وحدة التحكم، بل حجم نافذتها فقط، لذا تستنتجه Text.js: تقلّص اللوحة المثبتة innerWidth أو innerHeight بينما تبقى outer* ثابتة، وتُحل كل فرضية تثبيت وفق مستويات التكبير في Chrome. يُختار التطابق الأفضل. قِيست الثوابت (56 px من الحشو الأفقي، و104 px لعناصر واجهة وحدة التحكم، وتباعد صفوف قدره 14 px) في الواجهة الفعلية لأدوات DevTools.