Server-Side Rendering (SSR)
Overview
What is SSR?
Vue.js হল ক্লায়েন্ট-সাইড অ্যাপ্লিকেশন তৈরির জন্য একটি কাঠামো। ডিফল্টরূপে, Vue কম্পোনেন্টগুলি আউটপুট হিসাবে ব্রাউজারে DOM তৈরি করে এবং পরিচালনা করে। যাইহোক, সার্ভারের HTML স্ট্রিংগুলিতে একই কম্পোনেন্টগুলি রেন্ডার করা, সেগুলিকে সরাসরি ব্রাউজারে প্রেরণ করা এবং অবশেষে ক্লায়েন্টে একটি সম্পূর্ণ ইন্টারেক্টিভ অ্যাপে স্ট্যাটিক মার্কআপকে "hydrate" করাও সম্ভব।
একটি সার্ভার-রেন্ডার করা Vue.js অ্যাপটিকে "isomorphic" বা "universal" হিসাবেও বিবেচনা করা যেতে পারে, এই অর্থে যে আপনার অ্যাপের বেশিরভাগ কোড সার্ভার and ক্লায়েন্ট উভয়েই চলে৷
Why SSR?
একটি ক্লায়েন্ট-সাইড সিঙ্গেল-পেজ অ্যাপ্লিকেশন (SPA) এর তুলনায়, SSR-এর সুবিধা প্রাথমিকভাবে নিহিত:
দ্রুত সময় এ বিষয়অবজেক্ট: এটি ধীর ইন্টারনেট বা ধীর ডিভাইসে আরও বিশিষ্ট। সার্ভার-রেন্ডার করা মার্কআপের জন্য অপেক্ষা করতে হবে না যতক্ষণ না সমস্ত জাভাস্ক্রিপ্ট ডাউনলোড করা হয় এবং প্রদর্শিত হওয়ার জন্য কার্যকর করা হয়, তাই আপনার ব্যবহারকারী শীঘ্রই একটি সম্পূর্ণ-রেন্ডার করা পৃষ্ঠা দেখতে পাবে। এছাড়াও, প্রাথমিক ভিজিটের জন্য সার্ভার-সাইডে ডেটা আনা হয়, যার সম্ভবত ক্লায়েন্টের তুলনায় আপনার ডাটাবেসের সাথে দ্রুত সংযোগ রয়েছে। এটি সাধারণত উন্নত Core Web Vitals মেট্রিক্স, আরও ভাল ব্যবহারকারীর অভিজ্ঞতার ফলাফল করে এবং এমন অ্যাপ্লিকেশনগুলির জন্য গুরুত্বপূর্ণ হতে পারে যেখানে সময়-টু-কন্টেন্ট সরাসরি রূপান্তর হারের সাথে যুক্ত।
ইউনিফাইড মেন্টাল মডেল: আপনি ব্যাকএন্ড টেমপ্লেটিং সিস্টেম এবং ফ্রন্টএন্ড ফ্রেমওয়ার্কের মধ্যে এগিয়ে যাওয়ার পরিবর্তে একই ভাষা এবং একই ডিক্লেয়ার, কম্পোনেন্ট-ভিত্তিক মানসিক মডেল ব্যবহার করতে পারবেন।
বেটার এসইও: সার্চ ইঞ্জিন ক্রলাররা সরাসরি সম্পূর্ণ রেন্ডার করা পৃষ্ঠাটি দেখতে পাবে।
TIP
এখন পর্যন্ত, Google এবং Bing সিঙ্ক্রোনাস জাভাস্ক্রিপ্ট অ্যাপ্লিকেশনগুলিকে ঠিকঠাকভাবে সূচী করতে পারে। সিনক্রোনাস হচ্ছে মূল শব্দ। যদি আপনার অ্যাপটি একটি লোডিং স্পিনার দিয়ে শুরু হয়, তাহলে Ajax এর মাধ্যমে সামগ্রী নিয়ে আসে, ক্রলার আপনার শেষ হওয়ার জন্য অপেক্ষা করবে না। এর অর্থ হল আপনার যদি এসইও গুরুত্বপূর্ণ এমন পৃষ্ঠাগুলিতে অ্যাসিঙ্ক্রোনাসভাবে সামগ্রী আনা হয়, তাহলে SSR প্রয়োজন হতে পারে।
SSR ব্যবহার করার সময় বিবেচনা করার জন্য কিছু ট্রেড-অফ রয়েছে:
উন্নয়নের সীমাবদ্ধতা। ব্রাউজার-নির্দিষ্ট কোড শুধুমাত্র নির্দিষ্ট লাইফসাইকেল হুকের ভিতরে ব্যবহার করা যেতে পারে; কিছু বহিরাগত লাইব্রেরি একটি সার্ভার-রেন্ডার করা অ্যাপে চালানোর জন্য বিশেষ চিকিত্সার প্রয়োজন হতে পারে।
আরো জড়িত বিল্ড সেটআপ এবং স্থাপনার প্রয়োজনীয়তা. একটি সম্পূর্ণ স্ট্যাটিক এসপিএ থেকে ভিন্ন যা যেকোনো স্ট্যাটিক ফাইল সার্ভারে স্থাপন করা যেতে পারে, একটি সার্ভার-রেন্ডার করা অ্যাপের জন্য একটি পরিবেশ প্রয়োজন যেখানে একটি Node.js সার্ভার চলতে পারে।
আরও সার্ভার-সাইড লোড। Node.js-এ একটি সম্পূর্ণ অ্যাপ রেন্ডার করা কেবল স্ট্যাটিক ফাইল পরিবেশন করার চেয়ে বেশি CPU-নিবিড় হতে চলেছে, তাই আপনি যদি উচ্চ ট্র্যাফিক আশা করেন, তাহলে সংশ্লিষ্ট সার্ভার লোডের জন্য প্রস্তুত থাকুন এবং বুদ্ধিমানের সাথে ক্যাশিং কৌশল প্রয়োগ করুন।
আপনার অ্যাপের জন্য SSR ব্যবহার করার আগে, আপনাকে প্রথমে যে প্রশ্নটি জিজ্ঞাসা করা উচিত তা হল আপনার আসলে এটির প্রয়োজন আছে কিনা। এটি আপনার অ্যাপের জন্য সময়-টু-কন্টেন্ট কতটা গুরুত্বপূর্ণ তার উপর নির্ভর করে। উদাহরণস্বরূপ, আপনি যদি একটি অভ্যন্তরীণ ড্যাশবোর্ড তৈরি করেন যেখানে প্রাথমিক লোডের অতিরিক্ত কয়েকশ মিলিসেকেন্ড তেমন কোন ব্যাপার না, SSR একটি ওভারকিল হবে। যাইহোক, যে ক্ষেত্রে সময়-টু-কন্টেন্ট একেবারেই গুরুত্বপূর্ণ, SSR আপনাকে সর্বোত্তম সম্ভাব্য প্রাথমিক লোড কর্মক্ষমতা অর্জনে সহায়তা করতে পারে।
SSR vs. SSG
Static Site Generation (SSG), যাকে প্রি-রেন্ডারিংও বলা হয়, দ্রুত ওয়েবসাইট তৈরির আরেকটি জনপ্রিয় কৌশল। যদি একটি পৃষ্ঠা সার্ভার-রেন্ডার করার জন্য প্রয়োজনীয় ডেটা প্রতিটি ব্যবহারকারীর জন্য একই হয়, তাহলে প্রতিবার রিকোয়েস্ট আসার সময় পৃষ্ঠাটি রেন্ডার করার পরিবর্তে, আমরা এটিকে শুধুমাত্র একবার, সময়ের আগে, বিল্ড প্রক্রিয়া চলাকালীন রেন্ডার করতে পারি। প্রি-রেন্ডার করা পৃষ্ঠাগুলি তৈরি হয় এবং স্ট্যাটিক HTML ফাইল হিসাবে পরিবেশন করা হয়।
SSG একই কর্মক্ষমতা বৈশিষ্ট্য বজায় রাখে SSR অ্যাপের মতো: এটি টাইম-টু-কন্টেন্ট পারফরম্যান্স প্রদান করে। একই সময়ে, SSR অ্যাপের তুলনায় এটি ডেপ্লয় করা সহজ কারণ আউটপুটটি স্ট্যাটিক HTML এবং assets। এখানে কীওয়ার্ডটি হল স্ট্যাটিক: SSG শুধুমাত্র স্ট্যাটিক ডেটা প্রদানকারী পৃষ্ঠাগুলিতে প্রয়োগ করা যেতে পারে, যেমন ডেটা যা বিল্ড টাইমে পরিচিত এবং রিকোয়েস্ট মধ্যে পরিবর্তন করা যায় না। প্রতিবার ডেটা পরিবর্তিত হলে, একটি নতুন ডেপ্লয় প্রয়োজন হয়।
আপনি যদি শুধুমাত্র কিছু মার্কেটিং পৃষ্ঠার (যেমন /
, /about
, /contact
, ইত্যাদি) SEO উন্নত করার জন্য SSR ব্যবহার করছেন, তাহলে আপনি সম্ভবত SSR-এর পরিবর্তে SSG চান। SSG বিষয়বস্তু-ভিত্তিক ওয়েবসাইট যেমন ডকুমেন্টেশন সাইট বা ব্লগের জন্যও দুর্দান্ত। আসলে, আপনি এই মুহূর্তে যে ওয়েবসাইটটি পড়ছেন সেটি স্ট্যাটিকভাবে তৈরি করা হয়েছে VitePress, একটি Vue-চালিত স্ট্যাটিক সাইট জেনারেটর ব্যবহার করে।
Basic Tutorial
Rendering an App
চলুন কর্মে Vue SSR-এর সবচেয়ে নগ্ন-হাড়ের উদাহরণটি একবার দেখে নেওয়া যাক।
- একটি নতুন ডিরেক্টরি তৈরি করুন এবং এতে
cd
চালান npm init -y
চালানpackage.json
-এ"type": "module"
যোগ করুন যাতে Node.js ES modules mode চলেnpm install vue
চালান- একটি
example.js
ফাইল তৈরি করুন:
js
// this runs in Node.js on the server.
import { createSSRApp } from 'vue'
// Vue's server-rendering API is exposed under `vue/server-renderer`.
import { renderToString } from 'vue/server-renderer'
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `<button @click="count ">{{ count }}</button>`
})
renderToString(app).then((html) => {
console.log(html)
})
তারপর চালান:
sh
> node example.js
এটি কমান্ড লাইনে নিম্নলিখিত মুদ্রণ করা উচিত:
<button>1</button>
renderToString()
একটি Vue অ্যাপের উদাহরণ নেয় এবং একটি প্রতিশ্রুতি প্রদান করে যা অ্যাপের রেন্ডার করা HTML-এর সমাধান করে। Node.js Stream API অথবা ওয়েব স্ট্রিম API ব্যবহার করে রেন্ডারিং স্ট্রিম করাও সম্ভব। সম্পূর্ণ বিবরণের জন্য SSR API রেফারেন্স দেখুন।
তারপরে আমরা Vue SSR কোডটিকে একটি সার্ভার রিকোয়েস্ট হ্যান্ডলারে স্থানান্তর করতে পারি, যা সম্পূর্ণ পৃষ্ঠার এইচটিএমএল দিয়ে অ্যাপ্লিকেশন মার্কআপকে মুড়ে দেয়। আমরা পরবর্তী পদক্ষেপের জন্য express
ব্যবহার করব:
npm install express
চালান- নিম্নলিখিত
server.js
ফাইল তৈরি করুন:
js
import express from 'express'
import { createSSRApp } from 'vue'
import { renderToString } from 'vue/server-renderer'
const server = express()
server.get('/', (req, res) => {
const app = createSSRApp({
data: () => ({ count: 1 }),
template: `<button @click="count ">{{ count }}</button>`
})
renderToString(app).then((html) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>Vue SSR Example</title>
</head>
<body>
<div id="app">${html}</div>
</body>
</html>
`)
})
})
server.listen(3000, () => {
console.log('ready')
})
অবশেষে, node server.js
চালান এবং http://localhost:3000
দেখুন। আপনি দেখতে হবে যে পৃষ্ঠাটি বোতামের সাথে কাজ করছে।
Client Hydration
আপনি যদি বোতামটি ক্লিক করেন, আপনি লক্ষ্য করবেন যে নম্বরটি পরিবর্তন হচ্ছে না। আমরা ব্রাউজারে Vue লোড করছি না বলে এইচটিএমএল ক্লায়েন্টে সম্পূর্ণরূপে স্থির।
ক্লায়েন্ট-সাইড অ্যাপটিকে ইন্টারেক্টিভ করতে, Vue-কে hydration ধাপটি সম্পাদন করতে হবে। হাইড্রেশনের সময়, এটি একই Vue অ্যাপ্লিকেশন তৈরি করে যা সার্ভারে চালানো হয়েছিল, প্রতিটি কম্পোনেন্টকে DOM নোডের সাথে মেলে যা এটি নিয়ন্ত্রণ করা উচিত এবং DOM ইভেন্ট শ্রোতাদের সংযুক্ত করে।
হাইড্রেশন মোডে একটি অ্যাপ মাউন্ট করতে, আমাদের createApp()
এর পরিবর্তে createSSRApp()
ব্যবহার করতে হবে:
js
// this runs in the browser.
import { createSSRApp } from 'vue'
const app = createSSRApp({
// ...same app as on server
})
// mounting an SSR app on the client assumes
// the HTML was pre-rendered and will perform
// hydration instead of mounting new DOM nodes.
app.mount('#app')
Code Structure
লক্ষ্য করুন কিভাবে আমাদের সার্ভারের মতো একই অ্যাপ বাস্তবায়ন পুনরায় ব্যবহার করতে হবে। এখানেই আমাদের একটি SSR অ্যাপে কোড স্ট্রাকচার সম্পর্কে চিন্তা করা শুরু করতে হবে - কিভাবে আমরা সার্ভার এবং ক্লায়েন্টের মধ্যে একই অ্যাপ্লিকেশন কোড শেয়ার করব?
এখানে আমরা সবচেয়ে বেয়ার-বোন সেটআপ প্রদর্শন করব। প্রথমে, অ্যাপ তৈরির যুক্তিটিকে একটি ডেডিকেটেড ফাইল, app.js
-এ ভাগ করা যাক:
js
// app.js (shared between server and client)
import { createSSRApp } from 'vue'
export function createApp() {
return createSSRApp({
data: () => ({ count: 1 }),
template: `<button @click="count ">{{ count }}</button>`
})
}
এই ফাইল এবং এর নির্ভরতা সার্ভার এবং ক্লায়েন্টের মধ্যে ভাগ করা হয় - আমরা তাদের universal code বলি। সার্বজনীন কোড লেখার সময় আপনাকে অনেকগুলি বিষয়ের প্রতি মনোযোগ দিতে হবে, যেমন আমরা নীচে আলোচনা করব।
আমাদের ক্লায়েন্ট এন্ট্রি সার্বজনীন কোড আমদানি করে, অ্যাপ তৈরি করে এবং মাউন্টটি সম্পাদন করে:
js
// client.js
import { createApp } from './app.js'
createApp().mount('#app')
এবং সার্ভার রিকোয়েস্ট হ্যান্ডলারে একই অ্যাপ তৈরির যুক্তি ব্যবহার করে:
js
// server.js (irrelevant code omitted)
import { createApp } from './app.js'
server.get('/', (req, res) => {
const app = createApp()
renderToString(app).then(html => {
// ...
})
})
উপরন্তু, ব্রাউজারে ক্লায়েন্ট ফাইলগুলি লোড করার জন্য, আমাদেরও প্রয়োজন:
server.js
-এserver.use(express.static('.'))
যোগ করে ক্লায়েন্ট ফাইল পরিবেশন করুন।- HTML শেলে
<script type="module" src="/client.js"></script>
যোগ করে ক্লায়েন্ট এন্ট্রি লোড করুন। - HTML শেলে একটি Import Map যোগ করে ব্রাউজারে
import * from 'vue'
ব্যবহার সমর্থন করুন।
StackBlitz-এ সম্পূর্ণ উদাহরণ ব্যবহার করে দেখুন। বোতামটি এখন ইন্টারেক্টিভ!
Higher Level Solutions
উদাহরণ থেকে একটি প্রোডাকশন-প্রস্তুত SSR অ্যাপে যাওয়ার জন্য আরও অনেক কিছু জড়িত। আমাদের প্রয়োজন হবে:
সমর্থন Vue SFC এবং অন্যান্য বিল্ড ধাপ প্রয়োজনীয়তা. আসলে, আমাদের একই অ্যাপের জন্য দুটি বিল্ড সমন্বয় করতে হবে: একটি ক্লায়েন্টের জন্য এবং একটি সার্ভারের জন্য।
TIP
SSR-এর জন্য ব্যবহার করা হলে Vue কম্পোনেন্টগুলি ভিন্নভাবে কম্পাইল করা হয় - আরও দক্ষ রেন্ডারিং পারফরম্যান্সের জন্য ভার্চুয়াল DOM রেন্ডার ফাংশনের পরিবর্তে টেমপ্লেটগুলিকে স্ট্রিং কনক্যাটেনেশনে কম্পাইল করা হয়।
সার্ভার রিকোয়েস্ট হ্যান্ডলারে, সঠিক ক্লায়েন্ট-সাইড অ্যাসেট লিঙ্ক এবং সর্বোত্তম রিসোর্স ইঙ্গিত সহ HTML রেন্ডার করুন। আমাদের SSR এবং SSG মোডের মধ্যে স্যুইচ করতে হতে পারে, অথবা একই অ্যাপে উভয়কে মিশ্রিত করতে হতে পারে।
একটি সার্বজনীন পদ্ধতিতে রাউটিং, ডেটা আনয়ন এবং স্টেট ম্যানেজমেন্ট স্টোরগুলি পরিচালনা করুন৷
একটি সম্পূর্ণ বাস্তবায়ন বেশ জটিল হবে এবং আপনি যে বিল্ড টুলচেইনের সাথে কাজ করতে বেছে নিয়েছেন তার উপর নির্ভর করে। অতএব, আমরা একটি উচ্চ-স্তরের, মতামতযুক্ত সমাধান নিয়ে যাওয়ার সুপারিশ করি যা আপনার জন্য জটিলতা দূর করে। নীচে আমরা Vue ইকোসিস্টেমে কয়েকটি সুপারিশকৃত SSR সমাধান উপস্থাপন করব।
Nuxt
Nuxt হল একটি উচ্চ-স্তরের ফ্রেমওয়ার্ক যা Vue ইকোসিস্টেমের উপরে তৈরি করা হয়েছে যা সার্বজনীন Vue অ্যাপ্লিকেশন লেখার জন্য একটি সুবিন্যস্ত উন্নয়ন অভিজ্ঞতা প্রদান করে। আরও ভাল, আপনি এটিকে স্ট্যাটিক সাইট জেনারেটর হিসাবেও ব্যবহার করতে পারেন! আমরা অত্যন্ত এটি চেষ্টা করার সুপারিশ.
Quasar
Quasar হল একটি সম্পূর্ণ Vue-ভিত্তিক সমাধান যা আপনাকে SPA, SSR, PWA, মোবাইল অ্যাপ, ডেস্কটপ অ্যাপ, এবং ব্রাউজার এক্সটেনশনকে একটি কোডবেস ব্যবহার করে লক্ষ্য করতে দেয়। এটি শুধুমাত্র বিল্ড সেটআপ পরিচালনা করে না, তবে মেটেরিয়াল ডিজাইন অনুগত UI কম্পোনেন্টগুলির একটি সম্পূর্ণ সংগ্রহও সরবরাহ করে।
Vite SSR
Vite বিল্ট-ইন Vue সার্ভার-সাইড রেন্ডারিংয়ের জন্য সমর্থন প্রদান করে, তবে এটি ইচ্ছাকৃতভাবে নিম্ন-স্তরের। আপনি যদি সরাসরি Vite-এর সাথে যেতে চান, তাহলে vite-plugin-ssr দেখুন, একটি কমিউনিটি প্লাগইন যা আপনার জন্য অনেক চ্যালেঞ্জিং বিশদ বিমূর্ত করে।
এছাড়াও আপনি ম্যানুয়াল সেটআপ ব্যবহার করে একটি উদাহরণ Vue Vite SSR প্রজেক্ট খুঁজে পেতে পারেন এখানে, যা একটি হিসাবে কাজ করতে পারে ভিত্তি গড়ে তোলার জন্য। মনে রাখবেন এটি শুধুমাত্র তখনই সুপারিশ করা হয় যদি আপনি SSR/বিল্ড টুলের সাথে অভিজ্ঞ হন এবং সত্যিই উচ্চ-স্তরের আর্কিটেকচারের উপর সম্পূর্ণ নিয়ন্ত্রণ রাখতে চান।
Writing SSR-friendly Code
আপনার বিল্ড সেটআপ বা উচ্চ-স্তরের ফ্রেমওয়ার্ক পছন্দ নির্বিশেষে, কিছু নীতি রয়েছে যা সমস্ত Vue SSR অ্যাপ্লিকেশনগুলিতে প্রযোজ্য।
Reactivity on the Server
এসএসআর চলাকালীন, প্রতিটি রিকোয়েস্ট URL আমাদের অ্যাপ্লিকেশনের একটি পছন্দসই অবস্থায় ম্যাপ করে। কোন ব্যবহারকারীর মিথস্ক্রিয়া নেই এবং কোন DOM আপডেট নেই, তাই সার্ভারে প্রতিক্রিয়াশীলতা অপ্রয়োজনীয়। ডিফল্টরূপে, ভালো কর্মক্ষমতার জন্য SSR চলাকালীন প্রতিক্রিয়া নিষ্ক্রিয় করা হয়।
Component Lifecycle Hooks
যেহেতু কোন dynamic আপডেট নেই, যেমন লাইফসাইকেল হুক onMounted
or onUpdated
SSR চলাকালীন NOT কল করা হবে এবং শুধুমাত্র ক্লায়েন্টের উপর কার্যকর করা হবে।
আপনার এমন কোড এড়ানো উচিত যা পার্শ্বপ্রতিক্রিয়া তৈরি করে যার পরিচ্ছন্নতার প্রয়োজন setup()
অথবা এর মূল সুযোগ <script setup>
. এই ধরনের পার্শ্বপ্রতিক্রিয়ার একটি উদাহরণ হল setInterval
দিয়ে টাইমার সেট আপ করা। শুধুমাত্র ক্লায়েন্ট-সাইড কোডে আমরা একটি টাইমার সেটআপ করতে পারি এবং তারপরে এটি ছিঁড়ে ফেলতে পারি onBeforeUnmount
or onUnmounted
৷ যাইহোক, যেহেতু SSR চলাকালীন আনমাউন্ট হুকগুলিকে কখনই কল করা হবে না, তাই টাইমারগুলি চিরকালই থাকবে৷ এটি এড়াতে, আপনার পার্শ্ব-প্রতিক্রিয়া কোডটি এতে সরান ৷onMounted
পরিবর্তে.
Access to Platform-Specific APIs
ইউনিভার্সাল কোড প্ল্যাটফর্ম-নির্দিষ্ট API-এ অ্যাক্সেস অনুমান করতে পারে না, তাই যদি আপনার কোড সরাসরি ব্রাউজার-শুধুমাত্র গ্লোবাল যেমন window
বা document
ব্যবহার করে, তাহলে তারা Node.js-এ এক্সিকিউট করার সময় ত্রুটি নিক্ষেপ করবে এবং এর বিপরীতে।
সার্ভার এবং ক্লায়েন্টের মধ্যে কিন্তু বিভিন্ন প্ল্যাটফর্ম API-এর সাথে ভাগ করা কাজগুলির জন্য, একটি সর্বজনীন API-এর মধ্যে প্ল্যাটফর্ম-নির্দিষ্ট বাস্তবায়নগুলি মোড়ানো বা আপনার জন্য এটি করে এমন লাইব্রেরিগুলি ব্যবহার করার পরামর্শ দেওয়া হয়৷ উদাহরণস্বরূপ, আপনি সার্ভার এবং ক্লায়েন্ট উভয় ক্ষেত্রে একই ফেচ API ব্যবহার করতে node-fetch
ব্যবহার করতে পারেন।
ব্রাউজার-কেবল API-গুলির জন্য, সাধারণ পদ্ধতি হল ক্লায়েন্ট-শুধু লাইফসাইকেল হুকের মধ্যে অলসভাবে সেগুলি অ্যাক্সেস করা যেমন onMounted
.
মনে রাখবেন যে যদি একটি তৃতীয় পক্ষের লাইব্রেরি সর্বজনীন ব্যবহারের কথা মাথায় রেখে লেখা না হয় তবে এটি একটি সার্ভার-রেন্ডার করা অ্যাপে সংহত করা কঠিন হতে পারে। আপনি হতে পারে কিছু গ্লোবালকে উপহাস করে এটিকে কাজ করতে সক্ষম, তবে এটি হ্যাকি হবে এবং অন্যান্য লাইব্রেরির পরিবেশ সনাক্তকরণ কোডে হস্তক্ষেপ করতে পারে।
Cross-Request State Pollution
স্টেট ম্যানেজমেন্ট অধ্যায়ে, আমরা একটি রিঅ্যাক্টিভিটি এপিআই ব্যবহার করে সরল স্টেট ম্যানেজমেন্ট প্যাটার্ন চালু করেছি। একটি SSR প্রসঙ্গে, এই প্যাটার্নের জন্য কিছু অতিরিক্ত সমন্বয় প্রয়োজন।
প্যাটার্নটি জাভাস্ক্রিপ্ট মডিউলের রুট স্কোপে শেয়ার করা অবস্থা ঘোষণা করে। এটি তাদের singletons করে তোলে - অর্থাৎ আমাদের অ্যাপ্লিকেশনের সমগ্র লাইফসাইকেল জুড়ে প্রতিক্রিয়াশীল অবজেক্টর একটি মাত্র উদাহরণ রয়েছে। এটি একটি বিশুদ্ধ ক্লায়েন্ট-সাইড Vue অ্যাপ্লিকেশনে প্রত্যাশিত হিসাবে কাজ করে, যেহেতু আমাদের অ্যাপ্লিকেশনের মডিউলগুলি প্রতিটি ব্রাউজার পৃষ্ঠা দেখার জন্য নতুন করে শুরু করা হয়।
যাইহোক, একটি SSR প্রসঙ্গে, অ্যাপ্লিকেশন মডিউলগুলি সাধারণত সার্ভারে শুধুমাত্র একবার শুরু হয়, যখন সার্ভার বুট আপ হয়। একই মডিউল দৃষ্টান্তগুলি একাধিক সার্ভার রিকোয়েস্ট জুড়ে পুনরায় ব্যবহার করা হবে, এবং আমাদের সিঙ্গলটন স্টেট অবজেক্টগুলিও তাই হবে৷ যদি আমরা একটি ব্যবহারকারীর জন্য নির্দিষ্ট ডেটা সহ শেয়ার করা সিঙ্গলটন স্টেটকে পরিবর্তন করি, তবে এটি দুর্ঘটনাক্রমে অন্য ব্যবহারকারীর অনুরোধে ফাঁস হতে পারে। আমরা একে ক্রস-রিকোয়েস্ট স্টেট পলিউশন বলি।
আমরা প্রতিটি রিকোয়েস্ট ে সমস্ত জাভাস্ক্রিপ্ট মডিউলকে প্রযুক্তিগতভাবে পুনরায় আরম্ভ করতে পারি, ঠিক যেমন আমরা ব্রাউজারে করি। যাইহোক, জাভাস্ক্রিপ্ট মডিউল শুরু করা ব্যয়বহুল হতে পারে, তাই এটি সার্ভারের কার্যকারিতাকে উল্লেখযোগ্যভাবে প্রভাবিত করবে।
প্রস্তাবিত সমাধান হল প্রতিটি রিকোয়েস্ট ে - রাউটার এবং গ্লোবাল স্টোর সহ - সম্পূর্ণ অ্যাপ্লিকেশনটির একটি নতুন উদাহরণ তৈরি করা৷ তারপরে, আমাদের কম্পোনেন্টগুলিতে এটি সরাসরি আমদানি করার পরিবর্তে, আমরা app-level provide ব্যবহার করে শেয়ার্ড স্টেট প্রদান করি এবং এটি প্রয়োজনীয় কম্পোনেন্টগুলিতে ইনজেক্ট করি:
js
// app.js (shared between server and client)
import { createSSRApp } from 'vue'
import { createStore } from './store.js'
// called on each request
export function createApp() {
const app = createSSRApp(/* ... */)
// create new instance of store per request
const store = createStore(/* ... */)
// provide store at the app level
app.provide('store', store)
// also expose store for hydration purposes
return { app, store }
}
পিনিয়ার মতো স্টেট ম্যানেজমেন্ট লাইব্রেরিগুলি এটি মাথায় রেখে ডিজাইন করা হয়েছে। আরও বিশদ বিবরণের জন্য Pinia's SSR গাইড দেখুন।
Hydration Mismatch
যদি প্রি-রেন্ডার করা HTML এর DOM স্ট্রাকচার ক্লায়েন্ট-সাইড অ্যাপের প্রত্যাশিত আউটপুটের সাথে মেলে না, তাহলে একটি হাইড্রেশন অমিল ত্রুটি হবে। হাইড্রেশন অমিল সবচেয়ে সাধারণত নিম্নলিখিত কারণ দ্বারা প্রবর্তিত হয়:
টেমপ্লেটটিতে অবৈধ HTML নেস্টিং কাঠামো রয়েছে এবং রেন্ডার করা HTML ব্রাউজারের নেটিভ HTML পার্সিং আচরণ দ্বারা "সংশোধন" হয়েছে। উদাহরণস্বরূপ, একটি সাধারণ গোট হল যে
<div>
ভিতরে রাখা যাবে না<p>
এর ভিতরে রাখা যাবে না -ডিভ-ট্যাগ-ভিতরে-এটি):html<p><div>hi</div></p>
যদি আমরা এটি আমাদের সার্ভার-রেন্ডার করা HTML-এ তৈরি করি, তাহলে ব্রাউজারটি প্রথম
<p>
টি বন্ধ করে দিবে যখন<div>
সম্মুখীন হবে এবং এটিকে নিম্নলিখিত DOM কাঠামোতে পার্স করবে:html<p></p> <div>hi</div> <p></p>
রেন্ডারের সময় ব্যবহৃত ডেটা এলোমেলোভাবে উৎপন্ন মান ধারণ করে। যেহেতু একই অ্যাপ্লিকেশন দুবার চলবে - একবার সার্ভারে, এবং একবার ক্লায়েন্টে - এলোমেলো মান দুটি রানের মধ্যে একই হওয়ার নিশ্চয়তা নেই। এলোমেলো-মান-প্ররোচিত অমিল এড়াতে দুটি উপায় রয়েছে:
শুধুমাত্র ক্লায়েন্টের উপর এলোমেলো মানের উপর নির্ভর করে এমন অংশ রেন্ডার করতে
v-if
onMounted
ব্যবহার করুন। এটি সহজ করার জন্য আপনার ফ্রেমওয়ার্কের অন্তর্নির্মিত বৈশিষ্ট্যও থাকতে পারে, উদাহরণস্বরূপ VitePress-এ<ClientOnly>
কম্পোনেন্ট।একটি র্যান্ডম নম্বর জেনারেটর লাইব্রেরি ব্যবহার করুন যা বীজের সাহায্যে তৈরি করাকে সমর্থন করে এবং সার্ভার চালানোর গ্যারান্টি দেয় এবং ক্লায়েন্ট রান একই বীজ ব্যবহার করছে (যেমন ক্রমিক অবস্থায় বীজ অন্তর্ভুক্ত করে এবং ক্লায়েন্টের উপর এটি পুনরুদ্ধার করে)।
সার্ভার এবং ক্লায়েন্ট বিভিন্ন সময় অঞ্চলে রয়েছে। কখনও কখনও, আমরা ব্যবহারকারীর স্থানীয় সময়ে একটি টাইমস্ট্যাম্প রূপান্তর করতে চাই। যাইহোক, সার্ভার চালানোর সময় টাইমজোন এবং ক্লায়েন্ট চালানোর সময় টাইমজোন সবসময় এক হয় না, এবং আমরা সার্ভার চালানোর সময় ব্যবহারকারীর টাইমজোন নির্ভরযোগ্যভাবে নাও জানতে পারি। এই ধরনের ক্ষেত্রে, স্থানীয় সময় রূপান্তরটি শুধুমাত্র ক্লায়েন্ট-অপারেশন হিসাবে সঞ্চালিত হওয়া উচিত।
যখন Vue একটি হাইড্রেশন অমিলের সম্মুখীন হয়, তখন এটি স্বয়ংক্রিয়ভাবে পুনরুদ্ধার করার চেষ্টা করবে এবং ক্লায়েন্ট-সাইড স্টেটের সাথে মেলে প্রি-রেন্ডার করা DOM সামঞ্জস্য করবে। এটি ভুল নোড বাতিল করা এবং নতুন নোড মাউন্ট করার কারণে কিছু রেন্ডারিং কর্মক্ষমতা ক্ষতির দিকে পরিচালিত করবে, তবে বেশিরভাগ ক্ষেত্রে, অ্যাপটি প্রত্যাশিত হিসাবে কাজ চালিয়ে যাওয়া উচিত। এটি বলেছে, উন্নয়নের সময় হাইড্রেশনের অমিলগুলি দূর করা এখনও ভাল।
Custom Directives
যেহেতু বেশিরভাগ কাস্টম নির্দেশাবলী সরাসরি DOM ম্যানিপুলেশন জড়িত, সেগুলি SSR এর সময় উপেক্ষা করা হয়। যাইহোক, আপনি যদি নির্দিষ্ট করতে চান যে একটি কাস্টম নির্দেশিকা কীভাবে রেন্ডার করা উচিত (অর্থাৎ এটি রেন্ডার করা কম্পোনেন্টটিতে কোন বৈশিষ্ট্য যুক্ত করা উচিত), আপনি getSSRProps
নির্দেশিকা হুক ব্যবহার করতে পারেন:
js
const myDirective = {
mounted(el, binding) {
// client-side implementation:
// directly update the DOM
el.id = binding.value
},
getSSRProps(binding) {
// server-side implementation:
// return the props to be rendered.
// getSSRProps only receives the directive binding.
return {
id: binding.value
}
}
}
Teleports
SSR চলাকালীন টেলিপোর্টের বিশেষ হ্যান্ডলিং প্রয়োজন। যদি রেন্ডার করা অ্যাপে Teleports থাকে, তাহলে টেলিপোর্ট করা কন্টেন্ট রেন্ডার করা স্ট্রিংয়ের অংশ হবে না। একটি সহজ সমাধান হল শর্তসাপেক্ষে মাউন্টে টেলিপোর্ট রেন্ডার করা।
আপনার যদি টেলিপোর্ট করা বিষয়অবজেক্ট হাইড্রেট করার প্রয়োজন হয়, সেগুলি ssr প্রসঙ্গ অবজেক্টের teleports
কম্পিউটেড প্রপার্টির অধীনে প্রকাশ করা হয়:
js
const ctx = {}
const html = await renderToString(app, ctx)
console.log(ctx.teleports) // { '#teleported': 'teleported content' }
আপনাকে আপনার চূড়ান্ত পৃষ্ঠার HTML-এর সঠিক অবস্থানে টেলিপোর্ট মার্কআপটি ইনজেকশন করতে হবে যেভাবে আপনাকে মূল অ্যাপ মার্কআপটি ইনজেকশন করতে হবে।
TIP
টেলিপোর্ট এবং SSR একসাথে ব্যবহার করার সময় body
টার্গেট করা এড়িয়ে চলুন - সাধারণত, <body>
অন্যান্য সার্ভার-রেন্ডার করা সামগ্রী থাকবে যা টেলিপোর্টের পক্ষে হাইড্রেশনের জন্য সঠিক শুরুর অবস্থান নির্ধারণ করা অসম্ভব করে তোলে।
পরিবর্তে, একটি উত্সর্গীকৃত পাত্র পছন্দ করুন, যেমন <div id="teleported"></div>
যেটিতে শুধুমাত্র টেলিপোর্ট করা সামগ্রী রয়েছে৷