Skip to content

ההקלדה אינה מחשבת סגנון לכל המסמך בכל תו: כלל הבאנר בלי :has() - #53

Merged
Y-PLONI merged 7 commits into
Y-PLONI:mainfrom
Nathaniel-260:fix/typing-has-style-recalc
Sep 7, 2026
Merged

ההקלדה אינה מחשבת סגנון לכל המסמך בכל תו: כלל הבאנר בלי :has()#53
Y-PLONI merged 7 commits into
Y-PLONI:mainfrom
Nathaniel-260:fix/typing-has-style-recalc

Conversation

@Nathaniel-260

Copy link
Copy Markdown
Collaborator

מה קרה

„כשאני מקליד, לוקח כמה שניות עד שהתו מופיע.”

נמדד ב-Chrome על ה-dist הארוז, במסמך אמיתי של חמישה עמודים: על כל הקשה הדפדפן חישב סגנון מחדש (UpdateLayoutTree) לכל עץ המסמך — 2,748 אלמנטים, 60–115ms לחישוב — 42 פעמים ב-50 הקשות, עם 53 long tasks. במסמך ריק זה לא קרה. על מכונה עמוסה ובתוך ה-WebView של אוצריא זה מה שמצטבר ל„כמה שניות”.

סיבת השורש

לא הקוד שרץ בהקלדה (פחות מאחוז מהזמן היה של התוסף) אלא כלל CSS יחיד ב-src/styles/engine-chrome.css: ההסתרה של באנר edit-rejected של המנוע נכתבה כ-

.superdoc__mutation-status:has([data-superdoc-v2-edit-rejected]) { display: none; }

:has() שהעוגן שלו יושב בתוך .superdoc גורם ל-Blink לסמן את .superdoc כמושפע מ-:has(), ומאותו רגע כל הוספה או הסרה של צומת במסמך — כל תו — מתזמנת חישוב סגנון של תת-העץ כולו. ב-trace עם invalidationTracking: „Affected by :has()” על DIV.superdoc, „Invalidation set invalidates subtree”.

ההכרעה הייתה ניסוי מבוקר על אותו מסמך, בזמן ריצה, לפני ההקלדה:

מה נמחק מהגיליון חישובי סגנון של כל המסמך (50 הקשות) long tasks
כלום (בסיס) 42 53
כלל אקראי (.editor-stack__host--pending) 40 64
ה-:has() שברצועה 44 52
כלל הבאנר 0 3

התיקון

הכלל מסתיר את ה-<p> שנושא את התכונה כילד ישיר של העוטף, בלי :has():

.superdoc__mutation-status > [data-superdoc-v2-edit-rejected] { display: none; }

העוטף (SuperDoc.vue) הוא height: 0 בלי ריפוד ורקע, ולכן אין הבדל נראה. העיגון הסמנטי בתכונה נשמר.

מה מונע חזרה

  • סטטיtests/unit/css-hygiene.test.ts: כל :has() בגיליונות ובבלוקי <style> חייב להופיע ברשימה מאושרת עם נימוק. הרשימה מחזיקה כלל אחד (ברצועה, מחוץ לעץ המסמך — נמדד כבלתי מזיק), והבדיקה נופלת גם אם כלל מאושר נעלם.
  • דינמיnpm run check:typing-recalc (scripts/qa/typing-style-recalc-qa.mjs): בונה מסמך של ארבעה עמודים דרך ה-Document API, מקליד 40 תווים תחת trace של ה-renderer (חיבור CDP שני, כי Tracing.dataCollected הוא אירוע), וסופר חישובי סגנון של ≥1,000 אלמנטים. מוטציה נמדדה: על ה-dist הישן — 112 חישובים כאלה (1,716ms) → אדום; אחרי התיקון — 0 → ירוק. נוסף ל-verify:qa.
  • חוזהtests/contract/engine-edit-rejected-banner.test.ts נועל את הצורה: בלי :has(), > בין העוטף לתכונה, וה-<p> אכן ילד ישיר באריזה.

כלי אבחון

scripts/typing-latency-probe.mjs: זמן מלחיצה עד ציור, long tasks, הודעות קונסולה וקריאות למאחז לכל הקשה; --docx, --tab, --drop-css <regex> (הניסוי שלמעלה), --trace, ו---attach <port> לתוסף שרץ בתוך אוצריא (אחרי הרצה עם WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=<port>). מתועד ב-README, „איטיות בהקלדה”.

מה לא נשלח למעלה

גיליון המנוע (@superdoc/docx-engine, קנייני) גם משתמש ב-:has(), וזה מה שהופך :has() בצד המארח למסוכן. בלי הכלל שלנו התופעה אינה מופיעה, ולכן ההגנה כאן. הרישיון של המנוע אוסר לפרסם מדידות שלו; נרשם איכותית ב-docs/engine-gaps.md.

בדיקות שרצו

  • npm run typecheck — עבר
  • npm test — 185 קבצים, 3,903 בדיקות, כולן עברו
  • npm run build + npm run check:dist — עבר
  • npm run check:typing-recalc — ירוק על הבנייה הזאת, אדום על הבנייה שלפני התיקון
  • scripts/typing-latency-probe.mjs על המסמך שדווח: long tasks בזמן הקלדה 53 → 2

@Nathaniel-260
Nathaniel-260 marked this pull request as draft September 6, 2026 16:43
@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

אימות על מסמך גדול (165 עמודים, ‏193 אלף מילים, נוצר לבדיקה): אחרי שהפריסה הראשונית נחה, ההקלדה על הבנייה המתוקנת נותנת חציון 55–75ms מלחיצה עד ציור, p90 כ-100ms, ו-4 long tasks ב-60 הקשות — כמו במסמך של חמישה עמודים — ואפס חישובי סגנון של כל המסמך. הקומיט הנוסף משפר את scripts/typing-latency-probe.mjs לבדיקות כאלה (‎--open-wait, ‎--settle, ‎--trace-light, ‎--profile-interval).

@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

אימות בתוך אוצריא, עם הקשות אמיתיות (8c0ae81)

נמדד על התוסף כשהוא רץ בתוך ה‑WebView של אוצריא (WebView2 עם --remote-debugging-port), על מסמך אמיתי של חמישה עמודים בשני טורים עם הערות שוליים, בהקשות אמיתיות של מערכת ההפעלה (SendInput) אחרי לחיצת עכבר אמיתית במסמך:

  • ההקשה מגיעה לדף תוך מילישניות בודדות; בזמן ההקלדה אפס long tasks ואפס חישובי סגנון של המסמך כולו. כך גם בהקלדה חופשית של המשתמש עצמו שנרשמה ברקע.
  • מה שנשאר מורגש הוא שלב המארח, לא הדף: הפיקסלים מופיעים על המסך כ‑150ms אחרי שה‑renderer צייר אותם (WebView2 → Windows.Graphics.Capture → טקסטורת Flutter → raster, בבניית Debug של אוצריא). זה מחוץ לתוסף ולא נראה במדידה דרך CDP בלבד.
  • שני מצבים נראים כ„הקלדה איטית” ואינם כאלה: חלון ממוזער, או WebView שאוצריא השהתה — הדף hidden, rAF לא רץ. הכלי מזהה ומדפיס זאת לפני שהוא מתחיל.

הקומיט מוסיף את scripts/typing-latency-inapp.mjs שמודד את השרשרת כולה (הקשה → keydown → ציור → פיקסלים, --screen), ומתקן ב‑typing-latency-probe.mjs --attach לחיצה סינתטית שנחתה ברצועה כשהחלון צר. פירוט ב‑README, „איטיות בהקלדה”.

@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

המארח: PR לפורק של flutter_inappwebview

מה שנשאר אחרי התיקון כאן — כ‑150ms מהציור ב‑renderer ועד הפיקסלים על המסך — נחקר בצד המארח: Windows.Graphics.Capture מספק פריים בכל טיק של הקומפוזיטור גם כשה‑WebView סטטי, ו‑Flutter צייר ~60fps כל הזמן שתוסף על המסך (~430 ציורים ב‑5 שניות, otzaria.exe ~20% CPU בשקט). התיקון — השוואת הפריים על ה‑GPU ו‑notify ל‑Flutter רק כשפיקסל השתנה — ב‑Otzaria/flutter_inappwebview#19: 18 ציורים ב‑5 שניות (הבהוב הסמן), 0 כשאין שינוי, CPU ~4%. ההשהיה עד המסך לא השתנתה (ספירת ההופים זהה), אבל המכונה כבר לא מבזבזת ליבה על WebView דומם.

המדידות נעשו עם scripts/typing-latency-inapp.mjs (cc366f9 בענף הזה).

@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

עוד קומיט על הענף (8a74521): scripts/typing-latency-inapp.mjs מודד עכשיו את הגעת התו ל‑DOM ולא את המוטציה הראשונה אחרי ההקשה — זו שכבת הסמן, והיא מקדימה את התו בעשרות מילישניות, כך שהמדד הקודם דיווח „מהר” גם כשהתו איחר. הרישום הוא סדרה ומשויך לפי סדר, ולכן הוא תקף גם בהקלדה מהירה, ומודפס „ההקשה האחרונה → התו האחרון ב‑DOM”: המדד שמרגישים כשמקלידים מהר. --target בוחר איפה להקליד (כותרת ברוחב העמוד, טור שמאלי/ימני, שורה לפי טקסט).

מה שנמצא איתו, על המסמך המקורי של הדיווח: התחושה „בטורים זה איטי” לא אושרה — פסקה עם ריצת עיצוב אחת בתוך הטורים מקלידה כמו הכותרת גם בקצב מהיר. מה שכן איטי הוא פסקה עם ריצות עיצוב רבות, שהמנוע מסווג paragraph-complex-inline ומשליך מחדש בכל הקשה; ומכיוון שהקשות מעובדות אחת‑אחת בלי איחוד, הקלדה מהירה בפסקה כזאת נערמת לתור. זה במנוע, לא בתוסף ולא במארח, ומספריו אינם מתפרסמים. פירוט ב‑README תחת „בתוך אוצריא”.

@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

החלק של המנוע דווח ל-SuperDoc: superdoc/docx-editor#3984 — פסקה עם br/tab/הפניה להערת שוליים בתוך הפסקה כבדה פי שניים להקשה, וההקשות אינן מאוחדות. איכותי בלבד, עם מחולל מסמכי שחזור סינתטיים (gist). החלק של המארח נשאר לסבב הבא.

@Y-PLONI
Y-PLONI force-pushed the fix/typing-has-style-recalc branch from 8a74521 to 3214450 Compare September 7, 2026 13:04
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

תוצאות בדיקת תוספי אוצריא

מקור מפרט ה-API: GitHub (זמן אמת)

תוסף שגיאות אזהרות עיצוב סטטוס
וורד לאוצריא (com.otzaria_word_editor.superdoc) 0 0 0

הרצה מלאה

@Nathaniel-260

Copy link
Copy Markdown
Collaborator Author

תיקון (da9be97): המסקנה „המארח מייקר את ההקשה” נמדדה בזמן שסשן אחר בנה את אוצריא והריץ חבילת בדיקות על אותו מחשב (שתי ליבות). על מחשב שקט — אותה בנייה, אותו מסמך, אותה שורה — העורך עומד בקצב גם בפסקה עם br/tab, כמו ב-Chrome וב-Edge באותו רגע. README עודכן בהתאם (הטריגר: br/tab/הפניה להערת שוליים, לא מספר ריצות), ו-typing-latency-inapp.mjs מדפיס עכשיו את ה-CPU של שאר התהליכים בזמן הפרץ ומזהיר על עומס זר. תגובת תיקון מקבילה נוספה ב-superdoc/docx-editor#3984.

Nathaniel-260 and others added 7 commits September 7, 2026 19:54
„לוקח כמה שניות עד שהתו מופיע.” נמדד ב-Chrome על ה-dist, במסמך של חמישה
עמודים: על כל הקשה Blink חישב סגנון מחדש לכל עץ המסמך (2,748 אלמנטים,
60–115ms) — 42 פעמים ב-50 הקשות, 53 long tasks. הטריגר: הכלל שהסתיר את באנר
edit-rejected דרך `.superdoc__mutation-status:has([data-superdoc-v2-edit-rejected])`.
`:has()` שעוגנו בתוך `.superdoc` סימן את `.superdoc` כמושפע מ-:has(), ומאותו
רגע כל מוטציה במסמך תזמנה חישוב של תת-העץ כולו. הוכרע בניסוי מבוקר: מחיקת
הכלל הזה לבדו בזמן ריצה — 0 חישובים ו-3 long tasks; מחיקת כלל אחר — ללא שינוי.

הכלל מסתיר עכשיו את ה-<p> שנושא את התכונה כילד ישיר של העוטף (העוטף הוא
height: 0 בלי ריפוד; אין הבדל נראה). שני שערים נגד חזרה: css-hygiene חוסם כל
:has() שלא אושר במפורש, ו-check:typing-recalc מקליד תחת trace של ה-renderer
וסופר חישובי סגנון בגודל המסמך — אדום על הכלל הישן (112 ב-40 הקשות), ירוק
אחרי. scripts/typing-latency-probe.mjs הוא כלי האבחון, כולל --attach לתוסף
שרץ בתוך אוצריא.

vitest: 185 קבצים, 3,903 בדיקות; typecheck; check:dist; check:typing-recalc.
--open-wait ו---settle: מסמך של 165 עמודים נפתח בכ-14 שניות, ואחרי שהטקסט
כבר בעץ המנוע עוד „מסדר את התצוגה” כמה שניות. הקלדה בתוך החלון הזה מודדת
את הפתיחה ולא את ההקלדה: נמדדו 42 long tasks ו-p90 של ארבע שניות, ותחת
עומס trace המנוע חצה את שעון ה-1000ms שלו והוריד את הציור. עם שהות של 15
שניות אותו מסמך נותן חציון 55–75ms ו-4 long tasks ב-60 הקשות — כמו מסמך של
חמישה עמודים, ובלי חישוב סגנון של כל המסמך.

--trace-light: בלי invalidationTracking ו-stack, שמכבידים על הדף עצמו.
--profile-interval: 250µs היו כבדים על מסמך גדול; 1000µs מספיקים לשיוך.
scripts/typing-latency-inapp.mjs מודד את כל השרשרת בתוך ה-WebView של אוצריא — הקשת
מערכת ההפעלה (SendInput) → keydown בדף → ציור (rAF) → שינוי פיקסלים על המסך
(--screen) — אחרי לחיצת עכבר אמיתית, כי פוקוס JS אינו פוקוס המקלדת של המערכת.
מדפיס נראות ופוקוס לפני שמתחיל: חלון ממוזער או WebView מושהה הופכים את הדף
ל-hidden ונראים כהקלדה איטית.

ב-typing-latency-probe.mjs, במצב --attach, אין עוד לחיצה סינתטית: בחלון צר השורה
חורגת מהחלון והלחיצה נחתה ברצועה על „מסמך חדש”, והמדידה נעשתה במסמך אחר.

README: מה נמדד בתוך אוצריא אחרי התיקון, ומה נשאר למארח (שלב הצגת הפריים
WebView2 → Windows.Graphics.Capture → Flutter).
…יקסלים לאות עברית

הלחיצה האמיתית נוחתת לפי מיקום החלון הנוכחי (אוצריא מזיזה את החלון גם שניות
אחרי הפתיחה), נמנעת משורות עם קישורים (קישור פותח ספר ומחליף לשונית), ואם
הלשונית התחלפה בכל זאת — חוזרים אליה במקום להיכשל. סף השינוי על המסך ירד ל-60
פיקסלים: אות עברית קטנה משנה כ-100, והבהוב הסמן (~30) מסונן בבסיס הכפול.
…, ומדד ההיערמות בהקלדה מהירה

המוטציה הראשונה אחרי הקשה היא שכבת הסמן; התו עצמו מגיע עשרות מילישניות אחריה, ולכן המדד הקודם דיווח „מהר” גם כשלא. הרישום הוא סדרה ומשויך לפי סדר, כך שגם בהקלדה מהירה כל תו מוצמד להקשה שלו, ומודפס כמה אחרי ההקשה האחרונה הטקסט מתיישב. --target בוחר כותרת/טור/שורה לפי טקסט. ב-README: מה שנמדד תלוי במספר ריצות העיצוב בפסקה ולא בטורים.
… על המארח

„המארח מייקר כל הקשה” נמדד בזמן שסשן אחר בנה את אוצריא והריץ חבילת בדיקות על
אותו מחשב (שתי ליבות). על מחשב שקט — אותה בנייה, אותו מסמך, אותה שורה — העורך
עומד בקצב גם בפסקה עם br/tab, כמו ב-Chrome וב-Edge באותו רגע. הסקריפט מצלם
עכשיו TotalProcessorTime של כל התהליכים לפני ואחרי הפרץ, מדפיס „תהליכים אחרים”
עם השלושה הכבדים, ומזהיר כשהעומס הזר גדול. README: הטריגר הוא br/tab/הפניה
להערת שוליים (לא מספר ריצות), והתוצאה על מחשב שקט.
@Y-PLONI
Y-PLONI force-pushed the fix/typing-has-style-recalc branch from da9be97 to bb7b631 Compare September 7, 2026 16:55
@Y-PLONI
Y-PLONI merged commit 439bc16 into Y-PLONI:main Sep 7, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants