এতদিন আমরা ফাংশনালিটি নিয়ে কাজ করেছি — রাউটিং, ডেটা, Auth। এই পর্বে দুটো এমন বিষয় দেখব যা সরাসরি চোখে না পড়লেও ওয়েবসাইটের সাফল্যে বিশাল ভূমিকা রাখে — ছবি দ্রুত লোড হওয়া, আর Google-এ ঠিকমতো দেখানো। Next.js-এ দুটোই বিল্ট-ইন টুল দিয়ে অনেক সহজ।
সমস্যা — সাধারণ <img> ট্যাগের সীমাবদ্ধতা
HTML এর হাতেখড়ি সিরিজে আমরা <img src="..."> ব্যবহার করতাম। কিন্তু এতে —
- মূল ছবির পুরো সাইজই লোড হয়, স্ক্রিনে যত ছোট দেখাক না কেন
- কোনো lazy loading নেই — স্ক্রিনের বাইরের ছবিও সাথে সাথে লোড হয়
- ছবি লোড হওয়ার আগে পেজের লেআউট "লাফায়" (Cumulative Layout Shift), যা Cloudflare এর হাতেখড়ি পর্ব ১৩-এর Core Web Vitals-এ খারাপ প্রভাব ফেলে
next/image — সমাধান
import Image from "next/image";
export default function BookCard({ book }) {
return (
<div>
<Image
src={book.coverUrl}
alt={book.title}
width={200}
height={300}
/>
<p>{book.title}</p>
</div>
);
}
দেখতে সাধারণ <img>-এর মতোই, কিন্তু পেছনে অনেক কাজ হচ্ছে —
- স্বয়ংক্রিয় resize — ইউজারের ডিভাইস অনুযায়ী সঠিক সাইজের ছবি পাঠানো হয়
- WebP-এর মতো আধুনিক ফরম্যাট — ব্রাউজার সাপোর্ট করলে স্বয়ংক্রিয়ভাবে ছোট ফাইল সাইজে রূপান্তর
- Lazy loading — ডিফল্টভাবেই, স্ক্রিনে না আসা পর্যন্ত ছবি লোড হয় না
- width/height বাধ্যতামূলক — এতে ব্রাউজার আগে থেকেই জায়গা বরাদ্দ রাখে, লেআউট শিফট হয় না
External ছবির জন্য Domain অনুমতি
Firebase Storage বা Cloudflare R2 (পর্ব ৯ ও Cloudflare এর হাতেখড়ি পর্ব ৭)-এর মতো বাইরের সোর্স থেকে ছবি দেখাতে হলে, সেই ডোমেইনকে Next.js-কে জানাতে হয়।
// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "firebasestorage.googleapis.com",
},
{
protocol: "https",
hostname: "**.workers.dev", // Cloudflare Worker-এর মাধ্যমে R2 ছবি
},
],
},
};
এই কনফিগারেশন ছাড়া অচেনা ডোমেইনের ছবি ব্যবহারের চেষ্টা করলে Next.js একটা এরর দেখাবে — এটা একটা নিরাপত্তা ফিচার, যাতে কেউ ইচ্ছামতো যেকোনো URL দিয়ে অপ্টিমাইজেশন সার্ভিস অপব্যবহার করতে না পারে।
Priority — গুরুত্বপূর্ণ ছবির জন্য
পেজ লোড হওয়ার সাথে সাথেই দেখা যায় এমন ছবিতে (যেমন হিরো ইমেজ) lazy loading না চালিয়ে অগ্রাধিকার দেওয়া যায়।
<Image
src="/hero-banner.jpg"
alt="ArifStack Hero"
width={1200}
height={400}
priority // lazy loading স্কিপ, সাথে সাথে লোড
/>
Metadata API — SEO-এর জন্য title, description
পর্ব ১-এ layout.js শিখেছিলাম। প্রতিটা পেজের নিজস্ব title, description সেট করতে metadata এক্সপোর্ট করা হয়।
// app/about/page.js
export const metadata = {
title: "আমাদের সম্পর্কে | ArifStack",
description: "ArifStack একটা বাংলা প্রোগ্রামিং শেখার প্ল্যাটফর্ম, যেখানে বিগিনার থেকে শুরু করা যায়।",
};
export default function AboutPage() {
return <div>{/* ... */}</div>;
}
এই কোড Google-এর সার্চ রেজাল্টে যে title-description দেখা যায় (Cloudflare এর হাতেখড়ি পর্ব ১-এর meta description-এর মতোই ধারণা), সেটা কন্ট্রোল করে।
Dynamic Metadata — প্রতিটা বইয়ের জন্য আলাদা
পর্ব ২-এর [slug] ডাইনামিক রুটে, প্রতিটা পোস্টের জন্য ভিন্ন title দরকার — এর জন্য generateMetadata ফাংশন ব্যবহার হয়।
// app/blog/[slug]/page.js
export async function generateMetadata({ params }) {
const res = await fetch(`https://.../posts/${params.slug}.json`);
const post = await res.json();
return {
title: `${post.title} | ArifStack`,
description: post.excerpt,
};
}
export default async function BlogPost({ params }) {
// ... আসল পেজ কনটেন্ট ...
}
এখানে generateMetadata নিজেই একটা async ফাংশন, ঠিক পর্ব ৪-এর ডেটা ফেচিং প্যাটার্নের মতোই — প্রতিটা পোস্টের জন্য ডেটাবেজ থেকে সঠিক title বের করে আনছে।
Open Graph — সোশ্যাল মিডিয়া শেয়ারিং
Facebook বা টুইটারে লিংক শেয়ার করলে যে প্রিভিউ কার্ড দেখা যায় (ছবি, title, description), সেটা নিয়ন্ত্রণ করে Open Graph ট্যাগ — এটাও একই metadata অবজেক্টে যোগ করা যায়।
export async function generateMetadata({ params }) {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [post.coverUrl],
},
};
}
ইন্টারেক্টিভ — Metadata প্রিভিউ
নিচে একটা পোস্টের title আর description লিখলে দেখো Google সার্চ রেজাল্টে কেমন দেখাবে।
ভালো অভ্যাস
- সবসময় সাধারণ <img>-এর বদলে next/image ব্যবহার করুন — Core Web Vitals স্কোর সরাসরি প্রভাবিত করে
- height/width সঠিক অনুপাতে দিন — ভুল অনুপাত ছবি বিকৃত দেখাতে পারে
- প্রতিটা ডাইনামিক পেজে generateMetadata ব্যবহার করুন — সব পোস্টে একই title/description থাকলে SEO-তে কোনো সুবিধা হয় না
নিজে চেষ্টা করো
Exercise:
- নিজের একটা পেজে সাধারণ
<img>-এর বদলেnext/imageব্যবহার করো, DevTools-এর Network ট্যাবে ফাইল সাইজ কেমন কম আসছে দেখো। - একটা বাইরের ইমেজ ডোমেইন
next.config.js-এ যোগ করো, সেই ডোমেইনের ছবি দেখাও। - নিজের প্রতিটা পেজে
metadataএক্সপোর্ট করো, ব্রাউজার ট্যাবে title বদলাচ্ছে কিনা দেখো। - একটা ডাইনামিক রুটে
generateMetadataবসাও, "View Page Source" দিয়ে<title>ট্যাগ চেক করো।
পরের পর্বে যা থাকছে
পরের পর্বে আমরা শিখব Next.js + Cloudflare Pages Deployment — কীভাবে সম্পূর্ণ Next.js প্রজেক্ট Cloudflare Pages-এ ডেপ্লয় করতে হয়, এই সিরিজের এতদিনের সবকিছু একসাথে জুড়ে লাইভ করার আগের শেষ ধাপ।