הפער עד להידרציה
SSR בהזרמה יוצר פער בין הציור הראשון לסיום ההידרציה, וב-Suspense לכל גבול שמגיע באיחור יש פער משלו. בזמן הזה, אקורדיון המבוסס על useState נראה אך אינו מגיב, ואילו אקורדיון המבוסס על <details> עובד מהציור הראשון.
שני מסמכים מציגים אותו אקורדיון ללא תגית <script> כלשהי: אחד מבוסס על `<details>` ואחד מבוסס על `useState`. פתחו את שניהם: הראשון נפתח, והשני אינו יכול להיפתח. אפשר לבדוק זאת בקוד המקור.
המטרה היא אפס רינדורים מיותרים, אפס הפצה גורפת לכל צרכני ה-provider ואפס עבודת פריסה סינכרונית מקוד ה-JavaScript של הספרייה — לא אפס רינדורים, משום שהמצב חייב להתרנדר במקום כלשהו. ברירת המחדל היא אפס JavaScript, ושכבה דקה מתווספת רק כשנגישות מחייבת זאת.
רמות
כל רכיב מצהיר על רמה בקובץ מניפסט שה-build קורא. המניפסט קובע את תקציב הגודל, את בדיקת ה-lint לטוהר RSC, את סדרת בדיקות Playwright ואת תג הרמה בכל עמוד רכיב.
| רמה | תקציב | ללא JavaScript | משמעות |
|---|---|---|---|
| Tier 0 RSC — אפס JavaScript בצד הלקוח | 0 kB | עובר את סדרת הבדיקות ללא JavaScript במלואה. | המצב נמצא באלמנט מובנה, או שאין מצב. כל Hook של React אסור, כולל useMemo ו-useRef. |
| Tier 1 מעטפת RSC ואי לקוח דק | ≤ 1 kB | התנהגות מצומצמת, המתועדת לכל רכיב. | האלמנט המובנה עדיין מנהל את המצב. JavaScript רק מסנכרן ARIA או מוסיף את מה שחסר בפלטפורמה, כמו זיהוי כוונת ריחוף או סגירה אוטומטית. |
| Tier 2 רכיב לקוח — SSR לפני הידרציה | לכל רכיב | מציג מבנה HTML משמעותי לפני הידרציה. | נקודת כניסה אחת ללקוח. השרת מפיק HTML המבוסס על אלמנטים מובנים ככל האפשר; ניווט במקלדת, סינון וסנכרון ARIA ממתינים להידרציה. |
הרמות הן גם כלי למעבר הדרגתי: בדיקות הסף מופעלות לכל רכיב בנפרד, כך שהארכיטקטורה מתהדקת רכיב אחר רכיב.
מערך השכבות
@gunkin/uiify/hooks SSR-safe React hooks — the substrate
@gunkin/uiify/core headless behaviour: focus scope, dismiss layers, anchoring
@gunkin/uiify/elements native-mechanism wrappers — zero client JavaScript
@gunkin/uiify/components unstyled components, RSC by default
@gunkin/uiify/styles optional CSS design layerשכבות נמוכות לעולם אינן מייבאות שכבות גבוהות. @gunkin/uiify/elements היא המחמירה ביותר: היא רשאית לייבא רק את @gunkin/uiify/core/render וטיפוסים של React.
למה אלמנטים הם שכבה ציבורית
רוב האפליקציות לעולם אינן מייבאות ישירות מ-@gunkin/uiify/elements. השכבה מתפרסמת משתי סיבות.
ראשית, היא מאפשרת לאמת את התכנון. כשעמוד רכיב מציין _מבוסס על elements/dialog_, עמוד האלמנט מציג את מבנה ה-HTML המדויק ואת חוזה ה-data-* שמתחתיו.
שנית, הרכבה: אם מבנה חלקי הרכיב אינו מתאים לעיצוב שלכם, אפשר לבנות רכיב משלכם על אותו חיבור, במקום לממש מחדש את המנגנון.
מודול מצטרף לשכבה רק אם הוא עומד בכל חמשת הכללים: מנגנון מובנה אחד, ללא התנהגות JavaScript, לפחות שני צרכנים ב-@gunkin/uiify/components, מצב שבורר CSS יכול לקרוא, והפחתת כפילות HTML במקום הוספת שכבות תיווך.
המודולים נקראים על שם יכולות הפלטפורמה — details, dialog, popover, invoker — ולא על שם מושגי ממשק. רכיב לעולם אינו חולק שם עם אלמנט, ולכן Modal מבוסס על dialog. לעיון באלמנטים
למה React context אסור ב-Tier 0
העברת המצב ל-DOM אינה מועילה אם החלקים עדיין מתקשרים דרך React context. Server Components אינם יכולים להשתמש ב-context, ולכן Root ו-Item שחולקים provider אינם יכולים להתרנדר בשרת, גם אם ה-HTML שלהם מבוסס כולו על אלמנטים מובנים.
החיבורים חייבים לשרוד סריאליזציה, ולכן החלקים מתחברים דרך HTML: <details name> לקיבוץ, commandfor ו-popovertarget להפניות שהדפדפן פותר, ומזהים הנגזרים מה-props. ערך של useId אינו יכול להגיע לחלקים אחים ללא context.
<Accordion id="faq">
<Accordion.Item value="shipping"> {/* id="faq-shipping" */}המחיר: השורש זקוק ל-id. כשאין צורך בהרכבה, הרכיב מקבל נתונים ומרנדר את העץ בעצמו. על Server Components