پیشپرداخت بهمعنای ارسال نشانهگذاری عنصر سفارشی — ازجمله درخت سایه آن — از سرور است، بنابراین مؤلفه قبلاز اجرای هرگونه جاوا اسکریپت سبکبندی و ساختاردهی میشود. پایه اصلی پلاتفرم برای این کار Declarative Shadow DOM (DSD) است: تجزیهکننده ریشه سایه را فقط از HTML پیوست میکند، و عنصر بعداً توسط کلاس خود (درصورت ثبت شدن) ارتقا مییابد («هیدراته میشود»). از این الگو برای پردازش سمت سرور، جاریسازی، و اجتناب از فلش محتوای بدون سبک (FOUC) استفاده کنید.
Authoring a declarative shadow root
یک <template> را با مشخصه shadowrootmode بهعنوان اولین فرزند میزبان آشیانه کنید. تجزیهکننده محتوای آن را بهعنوان ریشه سایه پیوست میکند و الگو را برمیدارد؛ به هیچ اسکریپتی نیاز نیست.
<my-card>
<template shadowrootmode="open">
<style>
.card { border: 1px solid; border-radius: 8px; padding: 1rem; }
</style>
<div class="card">
<slot name="header"></slot>
<div class="body"><slot></slot></div>
</div>
</template>
<!-- Light DOM children are projected into the slots above. -->
<h2 slot="header">Server-rendered title</h2>
<p>Visible and styled before JS loads.</p>
</my-card>
زمانبندی آبرسانی
وقتی کلاس منطبق ثبت شود، مرورگر میزبان را ارتقا میدهد. چون ریشه سایه ازقبل وجود دارد، سازنده نباید بدون بررسی ریشه دوم را ایجاد کند:
class MyCard extends HTMLElement {
constructor() {
super();
// Reuse the server-rendered shadow root if present; only create one if absent.
if (!this.shadowRoot) {
this.attachShadow({ mode: 'open' });
this.shadowRoot.append(template.content.cloneNode(true));
}
// Hydrate in place: attach listeners once against existing markup (not unguarded
// in connectedCallback, which re-runs if the element moves in the DOM), and do
// NOT re-render; that would discard the server's DOM and flash.
this.shadowRoot.getElementById('toggle')
?.addEventListener('click', () => this.toggleAttribute('open'));
}
}
برای تقریباً همه موارد، shadowrootmode="open" (نه closed) را تنظیم کنید تا اسکریپتها و ابزارها بتوانند برای هیدراته کردن به this.shadowRoot دسترسی پیدا کنند. برای سریالسازی ریشه سایه موجود به HTML در سرور یا در آزمایشها، از getHTML({ serializableShadowRoots: true }) استفاده کنید و ریشه را با serializable: true پیوست کنید.
پرهیز از FOUC
DSD فقط درصورتی در اولین رنگآمیزی بهدرستی ارائه میشود که سبکها در داخل الگوِ اعلانی ارسال شوند. برای حفظ آن:
- سرویس مقایسه قیمت مؤلفه را داخل
<template shadowrootmode>(برچسب<style>یا<link>) قرار دهید، نه در برگه بارشده دستورگان جداگانه. - فقط برای سبکهایی که باید منتظر جاوااسکریپت بمانند، با
my-card:not(:defined) { … }جفت کنید — معمولاً قوانین محافظ سطح صفحه مانند محو شدن در نمونههای ارائهشده توسط کارخواه که گذر SSR را ازدست میدهند. اینها در برگه سبک نگارش light-DOM (صفحه) قرار دارند، زیرا ریشه سایه هنوز در آنجا وجود ندارد و انتخابکنندههای:hostاز بیرون اعمال نمیشوند. سبکهای ساختاری داخل الگوی DSD به چنین محافظی نیاز ندارند. - Do not re-render the shadow tree on hydration. نشانهگذاری سرور را بهعنوان معتبر درنظر بگیرید و رفتار را به آن پیوست کنید.
راهبردهای جایگزین
در موتورهایی که shadowrootmode را تجزیه نمیکنند، الگو بیاثر است و محتوای آن بهعنوان ریشه سایه پیوست نمیشود. این (Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode')) را شناسایی کنید و اگر وجود نداشت، ریشه سایه را بهطور الزامی از همان نشانهگذاری درطول ارتقا پیوست کنید تا مؤلفه همچنان ارائه شود.