預先轉譯是指從伺服器傳送自訂元素的標記 (包括其陰影樹狀結構),因此元件會在任何 JavaScript 執行之前設定樣式和結構。這項功能的主要平台原始碼是宣告式 Shadow DOM (DSD):剖析器只會從 HTML 附加 Shadow Root,而元素稍後會由其類別升級 (「凍結」) (如有註冊)。這個模式適用於伺服器端轉譯、串流,以及避免未套用樣式的內容閃爍 (FOUC)。
編寫宣告式 Shadow Root
在主機的第一個子項中,巢狀結構 <template> 搭配 shadowrootmode 屬性。剖析器會將範本內容附加為 Shadow Root,並移除範本,不需使用指令碼。
<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>
飲水時間
註冊相符的類別後,瀏覽器會升級主體。由於 Shadow Root 已存在,建構函式不得盲目建立第二個:
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 進行補充。如要在伺服器或測試中,將現有的 Shadow Root 序列化回 HTML,請使用 getHTML({ serializableShadowRoots: true }),並使用 serializable: true 附加根目錄。
避免 FOUC
只有在樣式位於宣告式範本內時,DSD 才會在首次繪製時正確算繪。如要保留這項設定,請按照下列步驟操作:
- 將元件 CSS 放在
<template shadowrootmode>(<style>標記或<link>) 內,而非放在由指令碼載入的獨立樣式表中。 - 只有在樣式必須等待 JS 時,才與
my-card:not(:defined) { … }搭配使用,通常是網頁層級的防護規則,例如在用戶端算繪的例項上淡出,而這些例項未通過 SSR。這些樣式位於 light-DOM (網頁) 樣式表中,因為 shadow root 尚未存在,且:host選取器不會從外部套用。DSD 範本中的結構樣式則不需要這類防護。 - 請勿在凍結狀態還原時重新轉譯 Shadow Tree。將伺服器標記視為權威,並將行為附加至該標記。
備用策略
在不剖析 shadowrootmode 的引擎中,範本會處於閒置狀態,且其內容不會附加為陰影根。偵測這個 (Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode')),如果不存在,請在升級期間從相同的標記強制附加 shadow root,讓元件仍可算繪。