SPA-এর বাইরে - আপনার PWA এর জন্য বিকল্প আর্কিটেকচার

চলুন... স্থাপত্য সম্পর্কে কথা বলি?

আমি একটি গুরুত্বপূর্ণ, কিন্তু সম্ভাব্য ভুল বোঝাবুঝির বিষয় নিয়ে আলোচনা করতে যাচ্ছি: আপনার ওয়েব অ্যাপের জন্য আপনি যে স্থাপত্য ব্যবহার করেন, এবং বিশেষ করে, একটি প্রগতিশীল ওয়েব অ্যাপ তৈরি করার সময় আপনার স্থাপত্য সংক্রান্ত সিদ্ধান্তগুলি কীভাবে কার্যকর হয়।

"স্থাপত্য" কথাটা অস্পষ্ট শোনাতে পারে, এবং কেন এটি গুরুত্বপূর্ণ তা তাৎক্ষণিকভাবে স্পষ্ট নাও হতে পারে। আচ্ছা, স্থাপত্য সম্পর্কে চিন্তা করার একটি উপায় হল নিজেকে নিম্নলিখিত প্রশ্নগুলি জিজ্ঞাসা করা: যখন একজন ব্যবহারকারী আমার সাইটের একটি পৃষ্ঠা পরিদর্শন করেন, তখন কোন HTML লোড হয়? এবং তারপর, যখন তারা অন্য পৃষ্ঠা পরিদর্শন করেন তখন কী লোড হয়?

এই প্রশ্নগুলির উত্তর সবসময় সহজ হয় না, এবং একবার আপনি প্রগতিশীল ওয়েব অ্যাপ সম্পর্কে চিন্তাভাবনা শুরু করলে, সেগুলি আরও জটিল হয়ে উঠতে পারে। তাই আমার লক্ষ্য হল আপনাকে এমন একটি সম্ভাব্য স্থাপত্যের মাধ্যমে পরিচালিত করা যা আমি কার্যকর বলে মনে করেছি। এই নিবন্ধ জুড়ে, আমি একটি প্রগতিশীল ওয়েব অ্যাপ তৈরির জন্য আমার নেওয়া সিদ্ধান্তগুলিকে "আমার পদ্ধতি" হিসাবে চিহ্নিত করব।

তোমার নিজস্ব PWA তৈরি করার সময় তুমি আমার পদ্ধতি ব্যবহার করতে পারো, কিন্তু একই সাথে, অন্যান্য বৈধ বিকল্পও আছে। আমার আশা, সবগুলো অংশ কীভাবে একসাথে খাপ খায় তা দেখলে তুমি অনুপ্রাণিত হবে এবং তোমার প্রয়োজন অনুসারে এটি কাস্টমাইজ করার ক্ষমতা পাবে।

স্ট্যাক ওভারফ্লো PWA

এই প্রবন্ধের সাথে আমি একটি Stack Overflow PWA তৈরি করেছি। আমি Stack Overflow পড়তে এবং অবদান রাখতে অনেক সময় ব্যয় করি, এবং আমি এমন একটি ওয়েব অ্যাপ তৈরি করতে চেয়েছিলাম যা কোনও নির্দিষ্ট বিষয়ের জন্য প্রায়শই জিজ্ঞাসিত প্রশ্নগুলি ব্রাউজ করা সহজ করে তুলবে। এটি পাবলিক Stack Exchange API এর উপরে তৈরি। এটি ওপেন সোর্স, এবং আপনি GitHub প্রকল্পে গিয়ে আরও জানতে পারবেন।

মাল্টি-পেজ অ্যাপস (MPAs)

বিস্তারিত আলোচনায় যাওয়ার আগে, আসুন কিছু শব্দ সংজ্ঞায়িত করি এবং অন্তর্নিহিত প্রযুক্তির কিছু অংশ ব্যাখ্যা করি। প্রথমে, আমি "মাল্টি পেজ অ্যাপস" বা "এমপিএ" বলতে যা পছন্দ করি তা কভার করব।

ওয়েবের শুরু থেকেই ব্যবহৃত ঐতিহ্যবাহী স্থাপত্যের জন্য MPA একটি অভিনব নাম। প্রতিবার যখনই একজন ব্যবহারকারী একটি নতুন URL-এ নেভিগেট করেন, তখন ব্রাউজারটি ধীরে ধীরে সেই পৃষ্ঠার জন্য নির্দিষ্ট HTML রেন্ডার করে। পৃষ্ঠার অবস্থা বা নেভিগেশনের মধ্যে থাকা বিষয়বস্তু সংরক্ষণের কোনও প্রচেষ্টা করা হয় না। প্রতিবার যখন আপনি একটি নতুন পৃষ্ঠা পরিদর্শন করেন, তখন আপনি নতুন করে শুরু করেন।

এটি ওয়েব অ্যাপ তৈরির জন্য সিঙ্গেল-পেজ অ্যাপ (SPA) মডেলের বিপরীত, যেখানে ব্যবহারকারী যখন একটি নতুন বিভাগ পরিদর্শন করেন তখন ব্রাউজারটি বিদ্যমান পৃষ্ঠাটি আপডেট করার জন্য জাভাস্ক্রিপ্ট কোড চালায়। SPA এবং MPA উভয়ই ব্যবহারের জন্য সমানভাবে বৈধ মডেল, তবে এই পোস্টের জন্য, আমি একটি বহু-পেজ অ্যাপের প্রেক্ষাপটে PWA ধারণাগুলি অন্বেষণ করতে চেয়েছিলাম।

নির্ভরযোগ্যভাবে দ্রুত

তুমি আমাকে (এবং আরও অসংখ্যকে) "প্রগতিশীল ওয়েব অ্যাপ" বা PWA শব্দটি ব্যবহার করতে শুনেছো। তুমি হয়তো ইতিমধ্যেই এই সাইটের অন্য কোথাও কিছু পটভূমির সাথে পরিচিত।

আপনি PWA কে একটি ওয়েব অ্যাপ হিসেবে ভাবতে পারেন যা প্রথম শ্রেণীর ব্যবহারকারীর অভিজ্ঞতা প্রদান করে এবং ব্যবহারকারীর হোম স্ক্রিনে সত্যিই একটি স্থান অর্জন করে। " FIRE ", যা Fast , I integrated, Relable এবং Engaging এর জন্য ব্যবহৃত হয়, একটি PWA তৈরি করার সময় যে সমস্ত বৈশিষ্ট্যগুলি সম্পর্কে চিন্তা করা উচিত তার সংক্ষিপ্তসার।

এই প্রবন্ধে, আমি সেই বৈশিষ্ট্যগুলির একটি উপসেটের উপর আলোকপাত করতে যাচ্ছি: দ্রুত এবং নির্ভরযোগ্য

দ্রুত: যদিও "দ্রুত" শব্দের অর্থ বিভিন্ন প্রেক্ষাপটে ভিন্ন, আমি নেটওয়ার্ক থেকে যতটা সম্ভব কম লোড করার গতির সুবিধাগুলি কভার করতে যাচ্ছি।

নির্ভরযোগ্য: কিন্তু র-স্পিড যথেষ্ট নয়। PWA-এর মতো অনুভব করার জন্য, আপনার ওয়েব অ্যাপটি নির্ভরযোগ্য হওয়া উচিত। এটিকে যথেষ্ট স্থিতিস্থাপক হতে হবে যাতে সর্বদা কিছু লোড করা যায়, এমনকি যদি এটি কেবল একটি কাস্টমাইজড ত্রুটি পৃষ্ঠাও হয়, নেটওয়ার্কের অবস্থা নির্বিশেষে।

নির্ভরযোগ্যভাবে দ্রুত: এবং পরিশেষে, আমি PWA সংজ্ঞাটি সামান্য পুনর্বিন্যাস করব এবং দেখব যে নির্ভরযোগ্যভাবে দ্রুত কিছু তৈরি করার অর্থ কী। কেবলমাত্র কম-বিলম্বিত নেটওয়ার্কে থাকলে দ্রুত এবং নির্ভরযোগ্য হওয়া যথেষ্ট নয়। নির্ভরযোগ্যভাবে দ্রুত হওয়ার অর্থ হল আপনার ওয়েব অ্যাপের গতি সামঞ্জস্যপূর্ণ, অন্তর্নিহিত নেটওয়ার্ক অবস্থা নির্বিশেষে।

প্রযুক্তি সক্ষম করা: সার্ভিস ওয়ার্কার্স + ক্যাশে স্টোরেজ API

PWA গুলি গতি এবং স্থিতিস্থাপকতার জন্য একটি উচ্চ স্তর প্রবর্তন করে। সৌভাগ্যবশত, ওয়েব প্ল্যাটফর্মটি এই ধরণের কর্মক্ষমতা বাস্তবে রূপ দেওয়ার জন্য কিছু বিল্ডিং ব্লক অফার করে। আমি পরিষেবা কর্মী এবং ক্যাশে স্টোরেজ API এর কথা বলছি।

আপনি এমন একটি পরিষেবা কর্মী তৈরি করতে পারেন যা আগত অনুরোধগুলি শোনে, কিছু নেটওয়ার্কে প্রেরণ করে এবং ভবিষ্যতে ব্যবহারের জন্য প্রতিক্রিয়ার একটি অনুলিপি ক্যাশ স্টোরেজ API এর মাধ্যমে সংরক্ষণ করে।

একজন পরিষেবা কর্মী ক্যাশে স্টোরেজ API ব্যবহার করে একটি নেটওয়ার্ক প্রতিক্রিয়ার একটি অনুলিপি সংরক্ষণ করছেন।

পরের বার যখন ওয়েব অ্যাপটি একই অনুরোধ করবে, তখন এর পরিষেবা কর্মী তার ক্যাশে পরীক্ষা করতে পারবে এবং কেবল পূর্বে ক্যাশে করা প্রতিক্রিয়াটি ফেরত দিতে পারবে।

নেটওয়ার্ক বাইপাস করে সাড়া দেওয়ার জন্য ক্যাশে স্টোরেজ API ব্যবহার করছেন একজন পরিষেবা কর্মী।

নির্ভরযোগ্যভাবে দ্রুত কর্মক্ষমতা প্রদানের জন্য যখনই সম্ভব নেটওয়ার্ক এড়িয়ে চলা একটি গুরুত্বপূর্ণ অংশ।

"আইসোমরফিক" জাভাস্ক্রিপ্ট

আরেকটি ধারণা যা আমি আলোচনা করতে চাই তা হল যা কখনও কখনও "আইসোমরফিক" বা "সর্বজনীন" জাভাস্ক্রিপ্ট নামে পরিচিত। সহজ কথায়, এটি এমন ধারণা যে একই জাভাস্ক্রিপ্ট কোড বিভিন্ন রানটাইম পরিবেশের মধ্যে ভাগ করা যেতে পারে। যখন আমি আমার PWA তৈরি করি, তখন আমি আমার ব্যাক-এন্ড সার্ভার এবং পরিষেবা কর্মীর মধ্যে জাভাস্ক্রিপ্ট কোড ভাগ করতে চেয়েছিলাম।

এইভাবে কোড শেয়ার করার জন্য অনেক বৈধ পন্থা আছে, কিন্তু আমার পন্থা ছিল ES মডিউলগুলিকে চূড়ান্ত সোর্স কোড হিসেবে ব্যবহার করা। তারপর আমি Babel এবং Rollup এর সংমিশ্রণ ব্যবহার করে সার্ভার এবং পরিষেবা কর্মীর জন্য সেই মডিউলগুলিকে ট্রান্সপাইল এবং বান্ডিল করেছিলাম। আমার প্রকল্পে, .mjs ফাইল এক্সটেনশন সহ ফাইলগুলি হল এমন কোড যা একটি ES মডিউলে থাকে।

সার্ভার

এই ধারণা এবং পরিভাষাগুলি মাথায় রেখে, আসুন আমরা কীভাবে আমার স্ট্যাক ওভারফ্লো PWA তৈরি করেছি তা দেখি। আমি আমাদের ব্যাকএন্ড সার্ভারটি কভার করে শুরু করব এবং ব্যাখ্যা করব যে এটি সামগ্রিক স্থাপত্যের সাথে কীভাবে খাপ খায়।

আমি স্ট্যাটিক হোস্টিংয়ের সাথে একটি ডাইনামিক ব্যাকএন্ডের সংমিশ্রণ খুঁজছিলাম, এবং আমার পদ্ধতি ছিল ফায়ারবেস প্ল্যাটফর্ম ব্যবহার করা।

যখন কোনও ইনকামিং রিকোয়েস্ট আসবে তখন ফায়ারবেস ক্লাউড ফাংশনগুলি স্বয়ংক্রিয়ভাবে একটি নোড-ভিত্তিক পরিবেশ তৈরি করবে এবং জনপ্রিয় এক্সপ্রেস HTTP ফ্রেমওয়ার্কের সাথে একীভূত হবে, যার সাথে আমি ইতিমধ্যেই পরিচিত ছিলাম। এটি আমার সাইটের সমস্ত স্ট্যাটিক রিসোর্সের জন্য আউট-অফ-দ্য-বক্স হোস্টিংও অফার করে। আসুন দেখে নেওয়া যাক সার্ভার কীভাবে রিকোয়েস্ট পরিচালনা করে।

যখন কোনও ব্রাউজার আমাদের সার্ভারের বিরুদ্ধে নেভিগেশন অনুরোধ করে, তখন এটি নিম্নলিখিত প্রবাহের মধ্য দিয়ে যায়:

সার্ভার-সাইডের নেভিগেশন প্রতিক্রিয়া তৈরির একটি সারসংক্ষেপ।

সার্ভার URL এর উপর ভিত্তি করে অনুরোধটি রুট করে এবং একটি সম্পূর্ণ HTML ডকুমেন্ট তৈরি করতে টেমপ্লেটিং লজিক ব্যবহার করে। আমি স্ট্যাক এক্সচেঞ্জ API থেকে ডেটার সংমিশ্রণ ব্যবহার করি, সেইসাথে সার্ভার স্থানীয়ভাবে সংরক্ষণ করে এমন আংশিক HTML টুকরো ব্যবহার করি। একবার আমাদের পরিষেবা কর্মী কীভাবে প্রতিক্রিয়া জানাতে হয় তা জানলে, এটি আমাদের ওয়েব অ্যাপে HTML স্ট্রিমিং শুরু করতে পারে।

এই ছবির দুটি অংশ আরও বিস্তারিতভাবে অনুসন্ধান করার মতো: রাউটিং এবং টেমপ্লেটিং।

রাউটিং

রাউটিংয়ের ক্ষেত্রে, আমার পদ্ধতি ছিল এক্সপ্রেস ফ্রেমওয়ার্কের নেটিভ রাউটিং সিনট্যাক্স ব্যবহার করা। এটি সহজ URL উপসর্গগুলির সাথে মিলিত হওয়ার জন্য যথেষ্ট নমনীয়, সেইসাথে URL গুলিও যা পাথের অংশ হিসাবে প্যারামিটার অন্তর্ভুক্ত করে। এখানে, আমি রুটের নামের মধ্যে একটি ম্যাপিং তৈরি করি যা অন্তর্নিহিত এক্সপ্রেস প্যাটার্নের সাথে মিলিত হবে।

const routes = new Map([
  ['about', '/about'],
  ['questions', '/questions/:questionId'],
  ['index', '/'],
]);

export default routes;

এরপর আমি সার্ভারের কোড থেকে সরাসরি এই ম্যাপিংটি উল্লেখ করতে পারি। যখন কোনও প্রদত্ত এক্সপ্রেস প্যাটার্নের সাথে মিল থাকে, তখন উপযুক্ত হ্যান্ডলার ম্যাচিং রুটের জন্য নির্দিষ্ট টেমপ্লেটিং লজিকের সাথে সাড়া দেয়।

import routes from './lib/routes.mjs';
app.get(routes.get('index'), as>ync (req, res) = {
  // Templating logic.
});

সার্ভার-সাইড টেমপ্লেটিং

আর টেমপ্লেটিং লজিকটি দেখতে কেমন? আচ্ছা, আমি এমন একটি পদ্ধতি নিয়েছিলাম যেখানে আংশিক HTML টুকরোগুলোকে একের পর এক ক্রমানুসারে একত্রিত করা হয়েছিল। এই মডেলটি স্ট্রিমিংয়ের জন্য ভালোভাবে কাজ করে।

সার্ভারটি তাৎক্ষণিকভাবে কিছু প্রাথমিক HTML বয়লারপ্লেট ফেরত পাঠায় এবং ব্রাউজারটি সেই আংশিক পৃষ্ঠাটি তাৎক্ষণিকভাবে রেন্ডার করতে সক্ষম হয়। সার্ভারটি বাকি ডেটা উৎসগুলিকে একত্রিত করার সাথে সাথে, ডকুমেন্টটি সম্পূর্ণ না হওয়া পর্যন্ত সেগুলি ব্রাউজারে স্ট্রিম করে।

আমি কী বলতে চাইছি তা বুঝতে, আমাদের একটি রুটের এক্সপ্রেস কোডটি একবার দেখে নিন:

app.get(routes.get('index'), async (req>, res) = {
  res.write(headPartial + navbarPartial);
  const tag = req.query.tag || DEFAULT_TAG;
  const data = await requestData(...);
  res.write(templates.index(tag, data.items));
  res.write(footPartial);
  res.end();
});

response অবজেক্টের write() পদ্ধতি ব্যবহার করে এবং স্থানীয়ভাবে সংরক্ষিত আংশিক টেমপ্লেটগুলি উল্লেখ করে, আমি কোনও বহিরাগত ডেটা উৎস ব্লক না করেই অবিলম্বে রেসপন্স স্ট্রিম শুরু করতে সক্ষম। ব্রাউজারটি এই প্রাথমিক HTML গ্রহণ করে এবং তাৎক্ষণিকভাবে একটি অর্থপূর্ণ ইন্টারফেস এবং লোডিং বার্তা রেন্ডার করে।

আমাদের পৃষ্ঠার পরবর্তী অংশে Stack Exchange API থেকে ডেটা ব্যবহার করা হয়েছে। সেই ডেটা পাওয়ার অর্থ হল আমাদের সার্ভারকে একটি নেটওয়ার্ক অনুরোধ করতে হবে। ওয়েব অ্যাপটি কোনও প্রতিক্রিয়া না পাওয়া পর্যন্ত এবং এটি প্রক্রিয়া না করা পর্যন্ত অন্য কিছু রেন্ডার করতে পারে না, তবে অন্তত ব্যবহারকারীরা অপেক্ষা করার সময় একটি ফাঁকা স্ক্রিনের দিকে তাকিয়ে থাকবেন না।

একবার ওয়েব অ্যাপটি স্ট্যাক এক্সচেঞ্জ API থেকে প্রতিক্রিয়া পেয়ে গেলে, এটি API থেকে ডেটা তার সংশ্লিষ্ট HTML-এ অনুবাদ করার জন্য একটি কাস্টম টেমপ্লেটিং ফাংশন কল করে।

টেমপ্লেটিং ভাষা

টেমপ্লেটিং একটি আশ্চর্যজনকভাবে বিতর্কিত বিষয় হতে পারে, এবং আমি যা নিয়ে এসেছি তা অনেকের মধ্যে একটি মাত্র। আপনি আপনার নিজস্ব সমাধানটি প্রতিস্থাপন করতে চাইবেন, বিশেষ করে যদি আপনার কোনও বিদ্যমান টেমপ্লেটিং কাঠামোর সাথে উত্তরাধিকারসূত্রে সম্পর্ক থাকে।

আমার ব্যবহারের ক্ষেত্রে যা যুক্তিসঙ্গত ছিল তা হল জাভাস্ক্রিপ্টের টেমপ্লেট লিটারেলের উপর নির্ভর করা, কিছু লজিককে সহায়ক ফাংশনে বিভক্ত করা। MPA তৈরির একটি ভালো দিক হল যে আপনাকে স্টেট আপডেট ট্র্যাক করে আপনার HTML পুনরায় রেন্ডার করতে হবে না, তাই একটি মৌলিক পদ্ধতি যা স্ট্যাটিক HTML তৈরি করে তা আমার জন্য কাজ করেছে।

তাহলে এখানে আমার ওয়েব অ্যাপের ইনডেক্সের ডায়নামিক HTML অংশটি কীভাবে টেমপ্লেট করছি তার একটি উদাহরণ দেওয়া হল। আমার রুটের মতো, টেমপ্লেটিং লজিকটি একটি ES মডিউলে সংরক্ষণ করা হয় যা সার্ভার এবং পরিষেবা কর্মী উভয়ের মধ্যেই আমদানি করা যেতে পারে।

export function index(tag, items) {
  const title = `<h3>Top "${escape(tag)}"< Qu>estions/h3`;
  cons<t form = `form me>tho<d=&qu>ot;GET".../form`;
  const questionCards = i>tems
    .map(item =
      questionCard({
        id: item.question_id,
        title: item.title,
      })
    )
    .join('&<#39;);
  const que>stions = `div id<=&qu>ot;questions"${questionCards}/div`;
  return title + form + questions;
}

এই টেমপ্লেট ফাংশনগুলি সম্পূর্ণ জাভাস্ক্রিপ্ট, এবং প্রয়োজনে লজিকগুলিকে ছোট, সহায়ক ফাংশনে বিভক্ত করা কার্যকর। এখানে, আমি API প্রতিক্রিয়াতে ফিরে আসা প্রতিটি আইটেমকে এমন একটি ফাংশনে পাস করি, যা সমস্ত উপযুক্ত বৈশিষ্ট্য সেট সহ একটি স্ট্যান্ডার্ড HTML উপাদান তৈরি করে।

function questionCard({id, title}) {
  return `<a class="card"
             href="/questions/${id}"
             data-cache-url=>"${<qu>estionUrl(id)}"${title}/a`;
}

বিশেষ করে লক্ষ্য করার মতো বিষয় হলো, আমি প্রতিটি লিঙ্কে একটি ডেটা অ্যাট্রিবিউট যোগ করি, data-cache-url , যা স্ট্যাক এক্সচেঞ্জ API URL-এ সেট করা থাকে যা সংশ্লিষ্ট প্রশ্নটি প্রদর্শনের জন্য আমার প্রয়োজন। এটা মনে রাখবেন। আমি পরে এটি আবার দেখব।

টেমপ্লেটিং সম্পূর্ণ হয়ে গেলে, আমি আমার পৃষ্ঠার HTML এর শেষ অংশটি ব্রাউজারে স্ট্রিম করি এবং স্ট্রিমটি শেষ করি। এটি ব্রাউজারকে ইঙ্গিত দেয় যে প্রগতিশীল রেন্ডারিং সম্পূর্ণ হয়েছে।

app.get(routes.get('index'), async (req>, res) = {
  res.write(headPartial + navbarPartial);
  const tag = req.query.tag || DEFAULT_TAG;
  const data = await requestData(...);
  res.write(templates.index(tag, data.items));
  res.write(footPartial);
  res.end();
});

তাহলে এটা আমার সার্ভার সেটআপের একটি সংক্ষিপ্ত সফর। যে ব্যবহারকারীরা প্রথমবার আমার ওয়েব অ্যাপটি দেখেন তারা সর্বদা সার্ভার থেকে প্রতিক্রিয়া পাবেন, কিন্তু যখন কোনও ভিজিটর আমার ওয়েব অ্যাপে ফিরে আসবেন, তখন আমার পরিষেবা কর্মী প্রতিক্রিয়া জানাতে শুরু করবেন। আসুন সেখানে ডুব দেই।

সেবা কর্মী

পরিষেবা কর্মীর ক্ষেত্রে নেভিগেশন প্রতিক্রিয়া তৈরির একটি সারসংক্ষেপ।

এই চিত্রটি পরিচিত মনে হওয়া উচিত—আমি আগে যেসব অংশ আলোচনা করেছি তার অনেকগুলি এখানে একটু ভিন্নভাবে সাজানো আছে। আসুন অনুরোধের ধারাটি দেখি, পরিষেবা কর্মীর কথা বিবেচনা করে।

আমাদের পরিষেবা কর্মী একটি নির্দিষ্ট URL-এর জন্য একটি ইনকামিং নেভিগেশন অনুরোধ পরিচালনা করে এবং ঠিক আমার সার্ভারের মতো, এটি কীভাবে প্রতিক্রিয়া জানাতে হবে তা নির্ধারণ করতে রাউটিং এবং টেমপ্লেটিং লজিকের সংমিশ্রণ ব্যবহার করে।

পদ্ধতিটি আগের মতোই, কিন্তু বিভিন্ন নিম্ন-স্তরের আদিম ব্যবহার করে, যেমন fetch() এবং Cache Storage API । আমি HTML প্রতিক্রিয়া তৈরি করতে সেই ডেটা উৎসগুলি ব্যবহার করি, যা পরিষেবা কর্মী ওয়েব অ্যাপে ফেরত পাঠায়।

ওয়ার্কবক্স

নিম্ন-স্তরের আদিমতা দিয়ে শুরু করার পরিবর্তে, আমি আমার পরিষেবা কর্মীকে উচ্চ-স্তরের লাইব্রেরির একটি সেটের উপরে তৈরি করতে যাচ্ছি যার নাম Workbox । এটি যেকোনো পরিষেবা কর্মীর ক্যাশিং, রাউটিং এবং প্রতিক্রিয়া তৈরির যুক্তির জন্য একটি শক্ত ভিত্তি প্রদান করে।

রাউটিং

ঠিক যেমন আমার সার্ভার-সাইড কোডের ক্ষেত্রে, আমার পরিষেবা কর্মীর জানা দরকার যে কীভাবে একটি ইনকামিং অনুরোধকে উপযুক্ত প্রতিক্রিয়া যুক্তির সাথে মেলাতে হয়।

আমার পদ্ধতি ছিল প্রতিটি এক্সপ্রেস রুটকে একটি সংশ্লিষ্ট রেগুলার এক্সপ্রেশনে অনুবাদ করা , regexparam নামক একটি সহায়ক লাইব্রেরি ব্যবহার করে। একবার সেই অনুবাদটি সম্পন্ন হয়ে গেলে, আমি রেগুলার এক্সপ্রেশন রাউটিংয়ের জন্য ওয়ার্কবক্সের অন্তর্নির্মিত সমর্থনের সুবিধা নিতে পারি।

রেগুলার এক্সপ্রেশনযুক্ত মডিউলটি আমদানি করার পর, আমি প্রতিটি রেগুলার এক্সপ্রেশন ওয়ার্কবক্সের রাউটারের সাথে নিবন্ধন করি। প্রতিটি রুটের ভিতরে আমি একটি প্রতিক্রিয়া তৈরি করার জন্য কাস্টম টেমপ্লেটিং লজিক প্রদান করতে সক্ষম। সার্ভিস ওয়ার্কারে টেমপ্লেটিং আমার ব্যাকএন্ড সার্ভারের তুলনায় একটু বেশি জড়িত, তবে ওয়ার্কবক্স অনেক ভারী জিনিসপত্র তুলতে সাহায্য করে।

import regExpRoutes from './regexp-routes.mjs';

workbox.routing.registerRoute(
  regExpRoutes.get('index')
  // Templating logic.
);

স্ট্যাটিক অ্যাসেট ক্যাশিং

টেমপ্লেটিং গল্পের একটি গুরুত্বপূর্ণ অংশ হল নিশ্চিত করা যে আমার আংশিক HTML টেমপ্লেটগুলি ক্যাশে স্টোরেজ API এর মাধ্যমে স্থানীয়ভাবে উপলব্ধ, এবং যখন আমি ওয়েব অ্যাপে পরিবর্তনগুলি স্থাপন করি তখন তা আপডেট রাখা হয়। ক্যাশে রক্ষণাবেক্ষণ হাতে করলে ত্রুটি-প্রবণ হতে পারে, তাই আমি আমার বিল্ড প্রক্রিয়ার অংশ হিসাবে প্রিক্যাশিং পরিচালনা করার জন্য ওয়ার্কবক্সের দিকে ঝুঁকে পড়ি।

আমি একটি কনফিগারেশন ফাইল ব্যবহার করে Workbox-কে কোন URL গুলি প্রিক্যাশে করতে হবে তা বলি, সেই ডিরেক্টরির দিকে নির্দেশ করে যেখানে আমার সমস্ত স্থানীয় সম্পদ এবং মিলের জন্য প্যাটার্নের একটি সেট রয়েছে। এই ফাইলটি স্বয়ংক্রিয়ভাবে Workbox-এর CLI দ্বারা পঠিত হয়, যা আমি প্রতিবার সাইটটি পুনর্নির্মাণের সময় চালানো হয়।

module.exports = {
  globDirectory: 'build',
  globPatterns: ['**/*.{html,js,svg}'],
  // Other options...
};

ওয়ার্কবক্স প্রতিটি ফাইলের বিষয়বস্তুর একটি স্ন্যাপশট নেয় এবং স্বয়ংক্রিয়ভাবে URL এবং সংশোধনের তালিকাটি আমার চূড়ান্ত পরিষেবা কর্মী ফাইলে ইনজেক্ট করে। প্রি-ক্যাশ করা ফাইলগুলিকে সর্বদা উপলব্ধ এবং আপডেট রাখার জন্য ওয়ার্কবক্সে এখন প্রয়োজনীয় সবকিছু রয়েছে। ফলাফল হল একটি service-worker.js ফাইল যাতে নিম্নলিখিতগুলির মতো কিছু থাকে:

workbox.precaching.precacheAndRoute([
  {
    url: 'partials/about.html',
    revision: '518747aad9d7e',
  },
  {
    url: 'partials/foot.html',
    revision: '69bf746a9ecc6',
  },
  // etc.
]);

যারা আরও জটিল বিল্ড প্রক্রিয়া ব্যবহার করেন, তাদের জন্য ওয়ার্কবক্সে কমান্ড লাইন ইন্টারফেস ছাড়াও একটি webpack প্লাগইন এবং একটি জেনেরিক নোড মডিউল উভয়ই রয়েছে।

স্ট্রিমিং

এরপর, আমি চাই যে পরিষেবা কর্মী সেই পূর্ব-ক্যাশ করা আংশিক HTML টি অবিলম্বে ওয়েব অ্যাপে স্ট্রিম করুক। এটি "নির্ভরযোগ্যভাবে দ্রুত" হওয়ার একটি গুরুত্বপূর্ণ অংশ - আমি সর্বদা স্ক্রিনে তাৎক্ষণিকভাবে অর্থপূর্ণ কিছু পাই। সৌভাগ্যবশত, আমাদের পরিষেবা কর্মীর মধ্যে Streams API ব্যবহার করে এটি সম্ভব হয়েছে।

এখন, তুমি হয়তো আগেও স্ট্রিমস এপিআই সম্পর্কে শুনেছো। আমার সহকর্মী জ্যাক আর্চিবল্ড বছরের পর বছর ধরে এর প্রশংসা করে আসছেন। তিনি সাহসী ভবিষ্যদ্বাণী করেছিলেন যে ২০১৬ হবে ওয়েব স্ট্রিমিংয়ের বছর। আর স্ট্রিমস এপিআই আজও ঠিক ততটাই অসাধারণ যতটা দুই বছর আগে ছিল, কিন্তু একটি গুরুত্বপূর্ণ পার্থক্য সহ।

যদিও তখন শুধুমাত্র Chrome Streams সমর্থন করত, Streams API এখন আরও ব্যাপকভাবে সমর্থিত । সামগ্রিক গল্পটি ইতিবাচক, এবং উপযুক্ত ফলব্যাক কোড সহ, আজ আপনার পরিষেবা কর্মীতে স্ট্রিম ব্যবহার করা থেকে আপনাকে কোনও বাধা নেই।

আচ্ছা... একটা জিনিস হয়তো তোমাকে থামিয়ে রাখছে, আর সেটা হলো Streams API আসলে কীভাবে কাজ করে তা নিয়ে তোমার মাথায় ঘুরপাক খাচ্ছে। এটি খুব শক্তিশালী প্রিমিটিভের একটি সেট প্রকাশ করে, এবং যারা ডেভেলপাররা এটি ব্যবহার করতে স্বাচ্ছন্দ্যবোধ করেন তারা জটিল ডেটা প্রবাহ তৈরি করতে পারেন, যেমন:

const stream = new ReadableStream({
  pull(controller) {
    return sources[0]
      .then(r => r.read())
      .then(result => {
        if (result.done) {
          sources.shift();
          if (sources.length === 0) return controller.close();
          return this.pull(controller);
        } else {
          controller.enqueue(result.value);
        }
      });
  },
});

কিন্তু এই কোডের সম্পূর্ণ তাৎপর্য বোঝা সবার জন্য নাও হতে পারে। এই যুক্তিটি বিশ্লেষণ করার পরিবর্তে, আসুন পরিষেবা কর্মী স্ট্রিমিং সম্পর্কে আমার পদ্ধতি সম্পর্কে কথা বলি।

আমি একটি নতুন, উচ্চ-স্তরের র‍্যাপার, workbox-streams ব্যবহার করছি। এটির সাহায্যে, আমি এটিকে স্ট্রিমিং সোর্সের মিশ্রণে প্রেরণ করতে পারি, ক্যাশে এবং রানটাইম ডেটা উভয় থেকে যা নেটওয়ার্ক থেকে আসতে পারে। ওয়ার্কবক্স পৃথক সোর্সগুলিকে সমন্বয় করে এবং সেগুলিকে একটি একক, স্ট্রিমিং প্রতিক্রিয়াতে একত্রিত করে।

অতিরিক্তভাবে, ওয়ার্কবক্স স্বয়ংক্রিয়ভাবে সনাক্ত করে যে স্ট্রিমস এপিআই সমর্থিত কিনা, এবং যখন এটি সমর্থিত নয়, তখন এটি একটি সমতুল্য, নন-স্ট্রিমিং প্রতিক্রিয়া তৈরি করে। এর অর্থ হল আপনাকে ফলব্যাক লেখার বিষয়ে চিন্তা করতে হবে না, কারণ স্ট্রিমগুলি 100% ব্রাউজার সমর্থনের কাছাকাছি।

রানটাইম ক্যাশিং

চলুন দেখে নেওয়া যাক আমার সার্ভিস ওয়ার্কার স্ট্যাক এক্সচেঞ্জ এপিআই থেকে রানটাইম ডেটা কীভাবে ব্যবহার করে। ওয়েব অ্যাপের স্টোরেজ যাতে সীমাহীনভাবে বৃদ্ধি না পায় তা নিশ্চিত করার জন্য আমি stale-while-revalidate ক্যাশিং কৌশলের জন্য Workbox এর বিল্ট-ইন সাপোর্ট ব্যবহার করছি, সাথে মেয়াদ শেষ করার পদ্ধতিও ব্যবহার করছি।

স্ট্রিমিং রেসপন্স তৈরির জন্য বিভিন্ন উৎস পরিচালনা করার জন্য আমি ওয়ার্কবক্সে দুটি কৌশল সেট আপ করেছি। কয়েকটি ফাংশন কল এবং কনফিগারেশনের মাধ্যমে, ওয়ার্কবক্স আমাদের এমন কিছু করতে দেয় যা অন্যথায় শত শত লাইনের হাতে লেখা কোডের প্রয়োজন হত।

const cacheStrategy = workbox.strategies.cacheFirst({
  cacheName: workbox.core.cacheNames.precache,
});

const apiStrategy = workbox.strategies.staleWhileRevalidate({
  cacheName: API_CACHE_NAME,
  plugins: [new workbox.expiration.Plugin({maxEntries: 50})],
});

প্রথম কৌশলটি আমাদের আংশিক HTML টেমপ্লেটের মতো আগে থেকে ক্যাশে করা ডেটা পড়ে।

অন্য কৌশলটি 50টি এন্ট্রিতে পৌঁছানোর পরে stale-while-revalidate ক্যাশিং লজিক, এবং সম্প্রতি ব্যবহৃত ক্যাশের মেয়াদ শেষ করার পদ্ধতি প্রয়োগ করে।

এখন যেহেতু আমার কাছে সেই কৌশলগুলি তৈরি হয়ে গেছে, এখন কেবল Workbox কে বলা বাকি আছে কিভাবে সেগুলি ব্যবহার করে একটি সম্পূর্ণ, স্ট্রিমিং প্রতিক্রিয়া তৈরি করতে হয়। আমি ফাংশন হিসাবে সোর্সের একটি অ্যারে পাস করি এবং সেই প্রতিটি ফাংশন অবিলম্বে কার্যকর করা হবে। Workbox প্রতিটি সোর্স থেকে ফলাফল নেয় এবং ক্রমানুসারে ওয়েব অ্যাপে স্ট্রিম করে, শুধুমাত্র যদি অ্যারের পরবর্তী ফাংশনটি এখনও সম্পূর্ণ না হয় তবে বিলম্ব হয়।

workbox.streams.strategy([
  () => cacheStrategy.makeRequest({request: '/head.html'})>,
  () = cacheStrategy.makeRequest({request: '/navbar.html'}),
  async >({event, url}) = {
    const tag = url.searchParams.get('tag') || DEFAULT_TAG;
    const listResponse = await apiStrategy.makeRequest(...);
    const data = await listResponse.json();
    return templates.index(tag, >data.items);
  },
  () = cacheStrategy.makeRequest({request: '/foot.html'}),
]);

প্রথম দুটি উৎস হল ক্যাশে স্টোরেজ API থেকে সরাসরি পঠিত প্রাক-ক্যাশেড আংশিক টেমপ্লেট, তাই এগুলি সর্বদা তাৎক্ষণিকভাবে উপলব্ধ থাকবে। এটি নিশ্চিত করে যে আমাদের পরিষেবা কর্মী বাস্তবায়ন আমার সার্ভার-সাইড কোডের মতো অনুরোধগুলির প্রতিক্রিয়া জানানোর ক্ষেত্রে নির্ভরযোগ্যভাবে দ্রুত হবে।

আমাদের পরবর্তী সোর্স ফাংশন স্ট্যাক এক্সচেঞ্জ API থেকে ডেটা সংগ্রহ করে এবং ওয়েব অ্যাপের প্রত্যাশিত HTML-এ প্রতিক্রিয়া প্রক্রিয়া করে।

stale-while-revalidate কৌশলের অর্থ হল যদি আমার কাছে এই API কলের জন্য পূর্বে ক্যাশে করা প্রতিক্রিয়া থাকে, তাহলে আমি তাৎক্ষণিকভাবে পৃষ্ঠায় স্ট্রিম করতে সক্ষম হব, এবং পরবর্তী বার অনুরোধ করার সময় ক্যাশে এন্ট্রিটি "ব্যাকগ্রাউন্ডে" আপডেট করব।

অবশেষে, আমি আমার ফুটারের একটি ক্যাশেড কপি স্ট্রিম করি এবং প্রতিক্রিয়া সম্পূর্ণ করার জন্য চূড়ান্ত HTML ট্যাগগুলি বন্ধ করি।

কোড শেয়ার করলে জিনিসগুলি সুসংগত থাকে

তুমি লক্ষ্য করবে যে সার্ভিস ওয়ার্কার কোডের কিছু অংশ পরিচিত মনে হচ্ছে। আমার সার্ভিস ওয়ার্কার যে আংশিক HTML এবং টেমপ্লেটিং লজিক ব্যবহার করে তা আমার সার্ভার-সাইড হ্যান্ডলারের সাথে একই রকম। এই কোড শেয়ারিং নিশ্চিত করে যে ব্যবহারকারীরা একটি ধারাবাহিক অভিজ্ঞতা পান, তারা প্রথমবার আমার ওয়েব অ্যাপে যান বা সার্ভিস ওয়ার্কার দ্বারা রেন্ডার করা কোনও পৃষ্ঠায় ফিরে যান। এটাই আইসোমরফিক জাভাস্ক্রিপ্টের সৌন্দর্য।

গতিশীল, প্রগতিশীল বর্ধন

আমি আমার PWA-এর জন্য সার্ভার এবং সার্ভিস ওয়ার্কার উভয়ই ঘুরে দেখেছি, কিন্তু শেষ একটা যুক্তি আছে: আমার প্রতিটি পৃষ্ঠা সম্পূর্ণরূপে স্ট্রিম করার পরে, অল্প পরিমাণে জাভাস্ক্রিপ্ট চলে।

এই কোডটি ধীরে ধীরে ব্যবহারকারীর অভিজ্ঞতা উন্নত করে, কিন্তু এটি গুরুত্বপূর্ণ নয় - ওয়েব অ্যাপটি চালানো না হলেও কাজ করবে।

পৃষ্ঠার মেটাডেটা

আমার অ্যাপটি API প্রতিক্রিয়ার উপর ভিত্তি করে একটি পৃষ্ঠার মেটাডেটা আপডেট করার জন্য ক্লায়েন্ট-সাইড JavaScipt ব্যবহার করে। যেহেতু আমি প্রতিটি পৃষ্ঠার জন্য একই প্রাথমিক ক্যাশেড HTML ব্যবহার করি, ওয়েব অ্যাপটি আমার ডকুমেন্টের মাথায় জেনেরিক ট্যাগ দিয়ে শেষ হয়। কিন্তু আমার টেমপ্লেটিং এবং ক্লায়েন্ট-সাইড কোডের মধ্যে সমন্বয়ের মাধ্যমে, আমি পৃষ্ঠা-নির্দিষ্ট মেটাডেটা ব্যবহার করে উইন্ডোর শিরোনাম আপডেট করতে পারি।

টেমপ্লেটিং কোডের অংশ হিসেবে, আমার পদ্ধতি হল সঠিকভাবে এস্কেপ করা স্ট্রিং ধারণকারী একটি স্ক্রিপ্ট ট্যাগ অন্তর্ভুক্ত করা।

const metadataScript = `<script>
  self._title = '${escape(item.title)<}';>
/script`;

তারপর, আমার পৃষ্ঠাটি লোড হয়ে গেলে, আমি সেই স্ট্রিংটি পড়ি এবং ডকুমেন্টের শিরোনাম আপডেট করি।

if (self._title) {
  document.title = unescape(self._title);
}

যদি আপনার নিজস্ব ওয়েব অ্যাপে পৃষ্ঠা-নির্দিষ্ট মেটাডেটার অন্য কোনও অংশ আপডেট করতে চান, তাহলে আপনি একই পদ্ধতি অনুসরণ করতে পারেন।

অফলাইন ইউএক্স

আমি যে আরেকটি প্রগতিশীল বর্ধিতকরণ যোগ করেছি তা আমাদের অফলাইন ক্ষমতার দিকে মনোযোগ আকর্ষণ করার জন্য ব্যবহৃত হয়। আমি একটি নির্ভরযোগ্য PWA তৈরি করেছি, এবং আমি চাই ব্যবহারকারীরা জানুক যে যখন তারা অফলাইনে থাকবেন, তখনও তারা পূর্বে পরিদর্শন করা পৃষ্ঠাগুলি লোড করতে পারবেন।

প্রথমে, আমি ক্যাশ স্টোরেজ API ব্যবহার করে পূর্বে ক্যাশ করা সমস্ত API অনুরোধের একটি তালিকা পাই, এবং আমি এটিকে URL-এর তালিকায় অনুবাদ করি।

আমি যে বিশেষ ডেটা অ্যাট্রিবিউটগুলির কথা বলেছিলাম , তাদের প্রতিটিতে প্রশ্ন প্রদর্শনের জন্য প্রয়োজনীয় API অনুরোধের URL থাকে, তা মনে আছে? আমি ক্যাশেড URL-এর তালিকার সাথে সেই ডেটা অ্যাট্রিবিউটগুলিকে ক্রস-রেফারেন্স করতে পারি এবং মিল না থাকা সমস্ত প্রশ্নের লিঙ্কের একটি অ্যারে তৈরি করতে পারি।

যখন ব্রাউজারটি অফলাইন অবস্থায় প্রবেশ করে, তখন আমি আনক্যাশেড লিঙ্কগুলির তালিকাটি লুপ করি এবং যেগুলি কাজ করবে না সেগুলি মুছে ফেলি। মনে রাখবেন যে এটি ব্যবহারকারীদের জন্য একটি দৃশ্যমান ইঙ্গিত যে তারা সেই পৃষ্ঠাগুলি থেকে কী আশা করবে - আমি আসলে লিঙ্কগুলি অক্ষম করছি না, বা ব্যবহারকারীকে নেভিগেট করতে বাধা দিচ্ছি না।

const apiCache = await caches.open(API_CACHE_NAME);
const cachedRequests = await apiCache.keys();
const cachedUrls = cachedRequests.map(request => request.url);

const cards = document.querySelectorAll('.card');
const uncachedCards = [...cards].filte>r(card = {
  return !cachedUrls.includes(card.dataset.cacheUrl);
});

const offlineHandle>r = () = {
  for (const uncachedCard of uncachedCards) {
    uncachedCard.style.opacity = '0.3';
  }
};

const onli>neHandler = () = {
  for (const uncachedCard of uncachedCards) {
    uncachedCard.style.opacity = '1.0';
  }
};

window.addEventListener('online', onlineHandler);
window.addEventListener('offline', offlineHandler);

সাধারণ সমস্যা

আমি এখন বহু-পৃষ্ঠার PWA তৈরির আমার পদ্ধতির একটি সফর করেছি। আপনার নিজস্ব পদ্ধতি তৈরি করার সময় আপনাকে অনেকগুলি বিষয় বিবেচনা করতে হবে এবং আপনি আমার চেয়ে ভিন্ন সিদ্ধান্ত নিতে পারেন। ওয়েব তৈরির ক্ষেত্রে এই নমনীয়তা একটি দুর্দান্ত দিক।

আপনার নিজস্ব স্থাপত্য সিদ্ধান্ত নেওয়ার সময় আপনি কিছু সাধারণ সমস্যায় পড়তে পারেন, এবং আমি আপনাকে কিছুটা কষ্ট থেকে রক্ষা করতে চাই।

সম্পূর্ণ HTML ক্যাশে করবেন না

আমি আপনার ক্যাশে সম্পূর্ণ HTML ডকুমেন্ট সংরক্ষণ না করার পরামর্শ দিচ্ছি। প্রথমত, এটি স্থানের অপচয়। যদি আপনার ওয়েব অ্যাপ প্রতিটি পৃষ্ঠার জন্য একই মৌলিক HTML কাঠামো ব্যবহার করে, তাহলে আপনাকে বারবার একই মার্কআপের কপি সংরক্ষণ করতে হবে।

আরও গুরুত্বপূর্ণ বিষয় হল, যদি আপনি আপনার সাইটের শেয়ার করা HTML কাঠামোতে কোনও পরিবর্তন আনেন, তাহলে পূর্বে ক্যাশে করা প্রতিটি পৃষ্ঠা এখনও আপনার পুরানো লেআউটের সাথে আটকে থাকবে। পুরাতন এবং নতুন পৃষ্ঠাগুলির মিশ্রণ দেখে একজন ফিরে আসা দর্শকের হতাশা কল্পনা করুন।

সার্ভার / পরিষেবা কর্মীদের প্রবণতা

আরেকটি বিপদ যা এড়িয়ে চলা উচিত তা হলো আপনার সার্ভার এবং পরিষেবা কর্মীর মধ্যে সিঙ্ক্রোনাইজেশনের অভাব। আমার পদ্ধতি ছিল আইসোমরফিক জাভাস্ক্রিপ্ট ব্যবহার করা, যাতে উভয় জায়গায় একই কোড চালানো যায়। আপনার বিদ্যমান সার্ভার আর্কিটেকচারের উপর নির্ভর করে, এটি সবসময় সম্ভব নয়।

আপনি যে স্থাপত্যগত সিদ্ধান্তই নিন না কেন, আপনার সার্ভার এবং আপনার পরিষেবা কর্মীতে সমতুল্য রাউটিং এবং টেমপ্লেটিং কোড চালানোর জন্য আপনার কিছু কৌশল থাকা উচিত।

সবচেয়ে খারাপ পরিস্থিতি

অসঙ্গত লেআউট / নকশা

এই সমস্যাগুলো উপেক্ষা করলে কী হবে? আচ্ছা, সব ধরণের ব্যর্থতা সম্ভব, কিন্তু সবচেয়ে খারাপ পরিস্থিতি হল যে একজন রিটার্নিং ব্যবহারকারী এমন একটি ক্যাশেড পৃষ্ঠা পরিদর্শন করেন যার লেআউট খুবই পুরনো - সম্ভবত এমন একটি যেখানে হেডার টেক্সট পুরনো, অথবা এমন CSS ক্লাসের নাম ব্যবহার করা হয় যা আর বৈধ নয়।

সবচেয়ে খারাপ পরিস্থিতি: ভাঙা রাউটিং

অন্যথায়, একজন ব্যবহারকারী এমন একটি URL দেখতে পেতে পারেন যা আপনার সার্ভার দ্বারা পরিচালিত হয়, কিন্তু আপনার পরিষেবা কর্মী দ্বারা পরিচালিত হয় না। জম্বি লেআউট এবং ডেড এন্ডে পূর্ণ একটি সাইট একটি নির্ভরযোগ্য PWA নয়।

সাফল্যের জন্য টিপস

কিন্তু আপনি একা নন! নিম্নলিখিত টিপসগুলি আপনাকে এই বিপদগুলি এড়াতে সাহায্য করতে পারে:

বহু-ভাষা বাস্তবায়ন আছে এমন টেমপ্লেটিং এবং রাউটিং লাইব্রেরি ব্যবহার করুন

জাভাস্ক্রিপ্ট বাস্তবায়ন আছে এমন টেমপ্লেটিং এবং রাউটিং লাইব্রেরি ব্যবহার করার চেষ্টা করুন। এখন, আমি জানি যে প্রতিটি ডেভেলপার আপনার বর্তমান ওয়েব সার্ভার থেকে স্থানান্তরিত হয়ে টেমপ্লেটিংয়ের ভাষা ব্যবহার করতে পারে না।

কিন্তু বেশ কিছু জনপ্রিয় টেমপ্লেটিং এবং রাউটিং ফ্রেমওয়ার্কের বাস্তবায়ন একাধিক ভাষায় করা হয়েছে। যদি আপনি এমন একটি খুঁজে পান যা জাভাস্ক্রিপ্টের পাশাপাশি আপনার বর্তমান সার্ভারের ভাষার সাথেও কাজ করে, তাহলে আপনি আপনার পরিষেবা কর্মী এবং সার্ভারকে সিঙ্ক্রোনাইজ রাখার এক ধাপ এগিয়ে গেছেন।

নেস্টেড টেমপ্লেটের পরিবর্তে ক্রমিক টেমপ্লেট পছন্দ করুন

এরপর, আমি ধারাবাহিক টেমপ্লেটের একটি সিরিজ ব্যবহার করার পরামর্শ দিচ্ছি যা একের পর এক স্ট্রিম করা যেতে পারে। আপনার পৃষ্ঠার পরবর্তী অংশগুলিতে আরও জটিল টেমপ্লেটিং লজিক ব্যবহার করা ঠিক আছে, যতক্ষণ না আপনি আপনার HTML এর প্রাথমিক অংশটি যত দ্রুত সম্ভব স্ট্রিম করতে পারেন।

আপনার সার্ভিস ওয়ার্কারে স্ট্যাটিক এবং ডাইনামিক উভয় কন্টেন্ট ক্যাশে করুন

সেরা পারফরম্যান্সের জন্য, আপনার সাইটের সমস্ত গুরুত্বপূর্ণ স্ট্যাটিক রিসোর্স প্রিক্যাশে করা উচিত। API অনুরোধের মতো গতিশীল কন্টেন্ট পরিচালনা করার জন্য আপনার রানটাইম ক্যাশিং লজিকও সেট আপ করা উচিত। ওয়ার্কবক্স ব্যবহারের অর্থ হল আপনি স্ক্র্যাচ থেকে সবকিছু বাস্তবায়নের পরিবর্তে ভালভাবে পরীক্ষিত, উৎপাদন-প্রস্তুত কৌশলগুলির উপরে তৈরি করতে পারেন।

শুধুমাত্র যখন একেবারে প্রয়োজন তখনই নেটওয়ার্কে ব্লক করুন

এবং এর সাথে সম্পর্কিত, আপনার কেবল তখনই নেটওয়ার্কে ব্লক করা উচিত যখন ক্যাশে থেকে কোনও প্রতিক্রিয়া স্ট্রিম করা সম্ভব না হয়। তাৎক্ষণিকভাবে একটি ক্যাশে করা API প্রতিক্রিয়া প্রদর্শন করলে প্রায়শই নতুন ডেটার জন্য অপেক্ষা করার চেয়ে আরও ভাল ব্যবহারকারীর অভিজ্ঞতা পাওয়া যায়।

রিসোর্স