একটি ডিরেক্টরি সাইট তৈরি করা শুনতে খুব সহজ মনে হতে পারে, যতক্ষণ না আপনি একটি কিউরেটেড সূচিপত্র প্রদর্শনের জন্য ডাটাবেস, ক্যাশিং লেয়ার এবং রিঅ্যাক্টিভ ফ্রন্ট-এন্ড ফ্রেমওয়ার্কের মতো জটিল বিষয়গুলো যুক্ত করতে গিয়ে পড়েন। আমি সম্প্রতি Social Tools List তৈরি করেছি, যা সোশ্যাল মিডিয়া সফটওয়্যার তুলনা করার একটি সাইট। আমার লক্ষ্য ছিল এটিকে দ্রুত অনলাইনে নিয়ে আসা, দ্রুতগতির রাখা এবং এমন কন্টেন্টের জন্য ইনফ্রাস্ট্রাকচার রক্ষণাবেক্ষণ এড়ানো যা কেবল তখনই পরিবর্তিত হয় যখন আমি কোনো টুল যোগ করি বা আপডেট করি। আমি একটি স্ট্যাটিক-ফার্স্ট স্ট্যাক বেছে নিয়েছি: সাইট জেনারেশনের জন্য Astro, স্ট্রাকচার্ড ডেটার জন্য TypeScript এবং ডেপ্লয়মেন্টের জন্য Cloudflare Workers। এর ফলে এমন একটি সাইট তৈরি হয়েছে যা তাৎক্ষণিকভাবে লোড হয়, হোস্ট করতে প্রায় কোনো খরচ নেই এবং এতে কোনো ডাটাবেস অ্যাডমিনিস্ট্রেশনের প্রয়োজন হয় না।
কেন ডিরেক্টরির জন্য স্ট্যাটিক-ফার্স্ট পদ্ধতিটি যুক্তিযুক্ত
অনেক ওয়েব অ্যাপ ডিফল্টভাবে সার্ভার রেন্ডারিং বা সিঙ্গেল-পেজ আর্কিটেকচার ব্যবহার করে কারণ এগুলো নিরাপদ এবং আধুনিক পছন্দ বলে মনে হয়। কিন্তু প্রতিটি সাইটেই প্রতিবার রিকোয়েস্টের সময় ডায়নামিক ইউজার ইনপুট আসে না। Social Tools List হলো একটি রিড-হেভি (read-heavy) রিসোর্স। তুলনা করার ডেটা তখনই পরিবর্তিত হয় যখন আমি একটি আপডেট পুশ করি, কোনো ভিজিটর রিফ্রেশ দিলেই নয়। আগে থেকেই HTML রেন্ডার করে রাখলে এজ (edge) লেভেলে ডাটাবেস কুয়েরি, অন-দ্য-ফ্লাই টেমপ্লেট কম্পাইলেশন বা ব্রাউজারে হাইড্রেশন ওভারহেডের প্রয়োজন থাকে না। আমি বিল্ড টাইমে সাইটটি জেনারেট করি, স্ট্যাটিক ফাইলগুলো ডেপ্লয় করি এবং একটি লাইটওয়েট ওয়ার্কারকে র্যাপার হিসেবে কাজ করতে দিই। এটি রেসপন্স টাইম কম রাখে এবং রানটাইম ফেইলিউরের একটি বড় অংশ দূর করে।
ডাটাবেসে নয়, TypeScript-এ ডেটা সংরক্ষণ করুন
আমি কোনো ডাটাবেস ব্যবহার করি না। ডিরেক্টরির প্রতিটি টুলকে একটি TypeScript অবজেক্ট হিসেবে সংজ্ঞায়িত করা হয়েছে যাতে একটি slug, name, domain এবং supported workflows-এর একটি অ্যারে থাকে। একটি সাধারণ এন্ট্রি দেখতে এরকম:
{
slug: 'buffer',
name: 'Buffer',
domain: 'buffer.com',
workflows: ['scheduling', 'analytics']
}
সাইট তৈরির জন্য ব্যবহৃত একই ভাষায় ডেটা সংরক্ষণ করার দুটি তাৎক্ষণিক সুবিধা রয়েছে। প্রথমত, পুল রিকোয়েস্টগুলো কন্টেন্ট রিভিউতে পরিণত হয়। যখন আমি কোনো টুল যোগ করি, তখন diff-এ সঠিক ফিল্ড এবং ভ্যালুগুলো দেখা যায়, ফলে একজন টিমমেট কোনো CMS ইন্টারফেস না শিখেই টাইপো বা ভুল ডোমেইন শনাক্ত করতে পারেন। দ্বিতীয়ত, TypeScript কম্পাইলার প্রতিটি রেকর্ডের গঠন নিশ্চিত করে। আমি যদি কোনো slug দিতে ভুলে যাই বা কোনো workflow key-তে বানান ভুল করি, তবে ভুল ডেটা কোনো পেজে পৌঁছানোর আগেই বিল্ড ফেইল করবে।
একটি ডাটাবেস ব্যবহার করলে মাইগ্রেশন, কানেকশন স্ট্রিং, ক্যাশিং স্ট্র্যাটেজি এবং ব্যাকআপ রুটিনের মতো বিষয়গুলো যুক্ত হয়ে যেত। কয়েকশ এন্ট্রি বিশিষ্ট একটি ডিরেক্টরি যা আমি ম্যানুয়ালি রক্ষণাবেক্ষণ করি, তার জন্য এই অতিরিক্ত ঝামেলা বা ওভারহেড কেবল কাজের গতি কমিয়ে দেয়। TypeScript মডিউলে স্ট্যাটিক ডেটা রাখা হলো এই মডেলের জন্য সবচেয়ে সাশ্রয়ী এবং সঠিক সিদ্ধান্ত। এখানে 'সঠিক' অংশটি গুরুত্বপূর্ণ। এটি কেবল টাকা বাঁচানোর বিষয় নয়; এটি এমন সব অ্যাবস্ট্রাকশন লেয়ার সরিয়ে ফেলা যা আমার কাছে নেই এমন সমস্যা সমাধান করার জন্য তৈরি করা হয়েছে।
রাউটিং এবং রেন্ডারিংয়ের দায়িত্ব Astro-কে দিন
Astro একটি মাত্র ডায়নামিক রুট থেকে প্রতিটি টুলের জন্য একটি করে HTML পেজ জেনারেট করে। আমি একটি লেআউট কম্পোনেন্ট সংজ্ঞায়িত করি এবং Astro স্বয়ংক্রিয়ভাবে প্রতিটি এন্ট্রির জন্য মেটাডেটা, হেডিং এবং স্ট্রাকচার্ড ডেটা তৈরি করে দেয়। যেহেতু একই ডেটাসেট মেইন ইনডেক্স, ওয়ার্কফ্লো ক্যাটাগরি হাব এবং প্রতিটি ডিটেইল পেজ পরিচালনা করে, তাই হোম পেজের কোনো কার্ড ডিটেইল পেজের বর্ণনার চেয়ে আলাদা কিছু দেখানোর কোনো সুযোগ নেই। প্রথাগত CMS সেটআপে আপনি প্রায়ই ডেটার অমিল (drift) দেখতে পান: API একটি ভার্সন দেয়, ক্যাশ অন্যটি এবং ক্লায়েন্ট-সাইড রেন্ডার তৃতীয়টি। একটি সিঙ্গেল সোর্স অফ ট্রুথ (single source of truth) থেকে স্ট্যাটিক জেনারেশন এটি প্রতিরোধ করে।
Astro-এর আইল্যান্ড আর্কিটেকচার (island architecture) পুরো পেজকে JavaScript দিয়ে ভারাক্রান্ত না করেই ছোট ছোট ইন্টারেক্টিভ অংশ যোগ করা সহজ করে তোলে। সাইটটি স্ট্যাটিক HTML হিসেবে কাজ করে এবং শুধুমাত্র ফিল্টারিং স্ক্রিপ্টটি DOM-এর নির্দিষ্ট অংশকে হাইড্রেশন (hydrate) করে। পুরো ডকুমেন্টটি কোনো ফ্রেমওয়ার্ক রানটাইম দিয়ে মোড়ানো থাকে না। Astro পেজ মেটাডেটাকেও অত্যন্ত গুরুত্ব দেয়। প্রতিটি টুল পেজ সরাসরি TypeScript রেকর্ড থেকে প্রাপ্ত নিজস্ব টাইটেল ট্যাগ এবং মেটা ডেসক্রিপশন পায়, তাই আমার আলাদা কোনো প্লাগইন বা হেড ম্যানেজমেন্ট লাইব্রেরির প্রয়োজন হয় না।
ফ্রেমওয়ার্ক ছাড়াই ফিল্টারিং
সার্চ এবং ফিল্টারিং করার জন্য ডেভেলপাররা প্রায়ই React, Vue বা কোনো ভারী স্টেট ম্যানেজমেন্ট লাইব্রেরি ইনস্টল করার কথা ভাবেন। আমি তা করিনি। Astro সার্ভারে সম্পূর্ণ লিস্টটিকে সাধারণ HTML হিসেবে রেন্ডার করে। এক কিলোবাইটেরও কম একটি ছোট ভ্যানিলা JavaScript স্ক্রিপ্ট ব্রাউজারে চলে এবং একটি workflow ট্যাগ বা টেক্সট ম্যাচ-এর ভিত্তিতে লিস্ট আইটেমগুলোর ডিসপ্লে প্রপার্টি পরিবর্তন (toggle) করে।
আপনি যদি API-চালিত ব্যাকগ্রাউন্ড থেকে আসেন, তবে সম্পূর্ণ মার্কআপ সার্ভ করা অদক্ষ মনে হতে পারে। কিন্তু একটি সাধারণ ডাইনামিক পদ্ধতির ওভারহেড বিবেচনা করুন। ব্রাউজার একটি JavaScript bundle ডাউনলোড করে, একটি component tree hydrate করে, একটি endpoint কল করে, JSON-এর জন্য অপেক্ষা করে এবং তারপর row-গুলো রেন্ডার করে। একশটির কম টুলের তালিকা থাকা একটি ডিরেক্টরির জন্য, ডকুমেন্টে ইতিমধ্যে থাকা div-গুলোকে হাইড করার চেয়ে এই প্রক্রিয়াটি ধীরগতির এবং কম নির্ভরযোগ্য। আমার স্ক্রিপ্টটি ফিল্টার বাটনে event listener যুক্ত করে, প্রতিটি row-তে থাকা data-workflow attribute পড়ে এবং অমিল হওয়া অংশগুলোকে hidden হিসেবে সেট করে। এই কাজটি সম্পন্ন হতে মাত্র মিলিসেকেন্ড সময় লাগে।
যেহেতু তালিকাটি প্রাথমিক HTML-এই উপস্থিত থাকে, তাই JavaScript ছাড়াই সাইটটি ব্যবহার করা সম্ভব। সার্চ ইঞ্জিন ক্রলারগুলো প্রতিটি লিঙ্ক এবং প্রতিটি বিবরণ দেখতে পায়। ধীরগতির নেটওয়ার্ক বা স্ক্রিপ্ট ব্লকার ব্যবহারকারীরাও সম্পূর্ণ ডিরেক্টরি দেখতে পান। ফিল্টারিং একটি বাড়তি সুবিধা, কোনো বাধা নয়।
কোড হিসেবে সাইটম্যাপ এবং রোবটস
Sitemaps এবং robots.txt কোনো হাতে লেখা afterthought নয়। এগুলো হলো Astro route যা একই dataset এবং URL helpers ব্যবহার করে...
