প্রি-রেন্ডারিং মানে হল সার্ভার থেকে কাস্টম এলিমেন্টের মার্কআপ — এর শ্যাডো ট্রি সহ — পাঠানো, যাতে কোনও জাভাস্ক্রিপ্ট রান করার আগে কম্পোনেন্টটি স্টাইল এবং স্ট্রাকচার করা হয়। এর জন্য প্রধান প্ল্যাটফর্ম প্রিমিটিভ হল ডিক্লারেটিভ শ্যাডো DOM (DSD): পার্সার শুধুমাত্র HTML থেকে শ্যাডো রুট অ্যাটাচ করে এবং এলিমেন্টটি পরে তার ক্লাস দ্বারা আপগ্রেড করা হয় ("হাইড্রেট করা"), যদি একটি রেজিস্টার করা থাকে। সার্ভার-সাইড রেন্ডারিং, স্ট্রিমিং এবং ফ্ল্যাশ অফ আনস্টাইলড কন্টেন্ট (FOUC) এড়ানোর জন্য এই প্যাটার্ন ব্যবহার করুন।
ডিক্লেরেটিভ শ্যাডো রুট তৈরি করা
হোস্টের প্রথম চাইল্ড হিসেবে shadowrootmode অ্যাট্রিবিউট সহ <template> নেস্ট করুন। পার্সার তার কন্টেন্টকে শ্যাডো রুট হিসেবে অ্যাটাচ করে এবং টেমপ্লেট সরিয়ে দেয়; কোনও স্ক্রিপ্টের প্রয়োজন হয় না।
<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 প্রথম পেইন্টে সঠিকভাবে রেন্ডার করে। সেটি সংরক্ষণ করতে:
- কম্পোনেন্ট CSS
<template shadowrootmode>-এর (একটি<style>ট্যাগ বা একটি<link>) ভিতরে রাখুন, আলাদা স্ক্রিপ্ট-লোডেড শিটে নয়। - শুধুমাত্র সেইসব স্টাইলের জন্য
my-card:not(:defined) { … }-এর সাথে পেয়ার করুন যেগুলিকে JS-এর জন্য অপেক্ষা করতে হবে — সাধারণত পেজ-লেভেল গার্ড রুল যেমন ক্লায়েন্ট-রেন্ডার করা ইনস্ট্যান্সে ফেড-আউট যা SSR পাস মিস করে। এগুলি লাইট-DOM (পৃষ্ঠা) স্টাইলশিটে থাকে, কারণ সেখানে এখনও শ্যাডো রুট নেই এবং:hostসিলেক্টর বাইরে থেকে প্রয়োগ করা হয় না। DSD টেমপ্লেটের মধ্যে স্ট্রাকচারাল স্টাইলের জন্য এই ধরনের কোনও গার্ডের প্রয়োজন নেই। - হাইড্রেশনে শ্যাডো ট্রি আবার রেন্ডার করবেন না। সার্ভার মার্কআপকে প্রামাণিক হিসেবে বিবেচনা করুন এবং এর সাথে আচরণ অ্যাটাচ করুন।
ফলব্যাক স্ট্র্যাটেজি
যেসব ইঞ্জিনে shadowrootmode পার্স করা হয় না, সেখানে টেমপ্লেট ইনার্ট থাকে এবং এর কন্টেন্ট শ্যাডো রুট হিসেবে অ্যাটাচ করা হয় না। এটি (Object.hasOwn(HTMLTemplateElement.prototype, 'shadowRootMode')) শনাক্ত করুন এবং অনুপস্থিত থাকলে, আপগ্রেড করার সময় একই মার্কআপ থেকে শ্যাডো রুটটি বাধ্যতামূলকভাবে অ্যাটাচ করুন যাতে কম্পোনেন্টটি এখনও রেন্ডার হয়।