Next.js এর হাতেখড়ি (পর্ব ১১) – Image ও SEO Optimization

Next.js Image ও SEO Optimization

এতদিন আমরা ফাংশনালিটি নিয়ে কাজ করেছি — রাউটিং, ডেটা, 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:

  1. নিজের একটা পেজে সাধারণ <img>-এর বদলে next/image ব্যবহার করো, DevTools-এর Network ট্যাবে ফাইল সাইজ কেমন কম আসছে দেখো।
  2. একটা বাইরের ইমেজ ডোমেইন next.config.js-এ যোগ করো, সেই ডোমেইনের ছবি দেখাও।
  3. নিজের প্রতিটা পেজে metadata এক্সপোর্ট করো, ব্রাউজার ট্যাবে title বদলাচ্ছে কিনা দেখো।
  4. একটা ডাইনামিক রুটে generateMetadata বসাও, "View Page Source" দিয়ে <title> ট্যাগ চেক করো।

পরের পর্বে যা থাকছে

পরের পর্বে আমরা শিখব Next.js + Cloudflare Pages Deployment — কীভাবে সম্পূর্ণ Next.js প্রজেক্ট Cloudflare Pages-এ ডেপ্লয় করতে হয়, এই সিরিজের এতদিনের সবকিছু একসাথে জুড়ে লাইভ করার আগের শেষ ধাপ।

একটি মন্তব্য পোস্ট করুন

নবীনতর পূর্বতন

যোগাযোগ ফর্ম