How To Configure MUI Theme with Next.js App Router

How To Configure MUI Theme with Next.js App Router

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

পেইজ রাউটারে যদি আমরা নেক্সট ব্যবহার করি তাহলে এর সমস্ত রাউটিং আমরা করতাম page ফোল্ডারের মধ্যে। এর মধ্যে তিনটি মূল ফাইল নিয়ে আমরা কাজ করতাম।

  • _document.tsx: এখানে আমরা কাস্টম head এলিমেন্ট অ্যাড করতাম, এইচটিএমএল স্ট্রাকচার কাস্টমাইজ করতাম এবং কোনো ধরণের সিএসএস লাইব্রেরি যার সার্ভার সাইড রেন্ডারিং দরকার সেটার প্রোভাইডার দিয়ে আমরা আমাদের অ্যাপ্লিকেশনকে র‍্যাপ করে দিতাম।
  • _app.jsx: এখানে মূলত আমরা লেআউট কাস্টমাইজেশন, গ্লোবাল সিএসএস ইমপোর্টিং, কাস্টম ডাটা ফেচিং এবং কাস্টম প্রোভাইডার এবং কনটেক্সট র‍্যাপ করার জন্য ব্যবহার করতাম।
  • index.tsx: এখানে আমরা আমাদের পেইজের যাবতীয় কনটেন্ট লিখতাম।

অ্যাপ রাউটারে রাউটিং এর কাজগুলো করতে হয় app ফোল্ডারের মধ্যে। এর মধ্যে মূলত দুইটি ফাইল থাকে। layout.jsx এবং page.jsx। এছাড়াও আরো অনেকে ফাইল থাকতে পারে আমাদের প্রজেক্টের স্ট্রাকচার অনুসারে। সেগুলো সব নেক্সট এর ডকুমেন্টেশনে লেখা আছে। আমি সেগুলো আর তুললাম না এখানে। এই দুইটা ফাইল সম্পর্কে একটু ধারণা দিই।

  • layout.jsx: পেইজ রাউটারের _document.tsx + _app.jsx = অ্যাপ রাউটারের layout.jsx। তার মানে ঐ দুইটা ফাইলে আমরা যা যা করতে পারতাম সব এখন এই একটা ফাইলেই আমরা করতে পারি। এবং এখানের সমস্তা কনটেন্ট পুরো প্রজেক্টের জন্য অ্যাপ্লিকেবল হবে।
  • page.jsx: এখানে আমরা আমাদের পেইজের যাবতীয় কন্টেন্ট লিখতে পারি।

layout.jsx সবসময় সার্ভার সাইড রেন্ডারিং করে। ক্লায়েন্ট সাইড রেন্ডারিং সে করে না। আগের পেইজ রাউটারে ক্লায়েন্ট সাইড এবং সার্ভার সাইড রেন্ডারিং এর জন্য দুইটা আলাদা আলাদা ফাইল থাকায় আমরা সহজে সার্ভার সাইডের কনটেন্ট _document.tsx এ এবং ক্লায়েন্ট সাইডের কনটেন্ট _app.jsx এ লিখতে পারতাম। এখন আমাদের যে ক্লায়েন্ট সাইড রেন্ডারিং হুক বা কনটেক্সট আছে সেগুলো যদি আপনাকে ক্লায়েন্ট সাইডে রেন্ডার করতে হয় সেই ফাইলের উপরে বা সেই কম্পোনেন্ট বা কনটেক্সট অন্য যে কম্পোনেন্টে ব্যবহার হচ্ছে তার উপরে অবশ্যই use client; লিখে দিতে হবে। এখন যদি আমরা কাস্টম হুক বা কম্পোনেন্ট বা কনটেক্সট যদি বানাই সেক্ষেত্রে আমরা আমাদের কম্পোনেন্টের উপর নাহয় use client; লিখে দিলাম। কিন্তু MUI এর থিম এর ক্ষেত্রে যখন আমরা গ্লোবালি এই থিমকে অ্যাপ্লাই করার জন্য লে-আউটে যখনই ThemeProvider দিয়ে র‍্যাপ করতে যাবো তখনই সে একটা এরর শো করবে, যে সার্ভার সাইডে আমরা ক্লায়েন্ট সাইড রেন্ডারিং করতে পারবো না। একটু কোড করে বুঝাই।

import { ThemeProvider } from '@mui/material';
import theme from '../themes/theme';

export const metadata = {
    title: 'test',
    description: 'test',
    viewport: 'width=device-width, initial-scale=1',
};

const RootLayout = ({ children }) => (
    <html lang="en">
        <body>
            <ThemeProvider theme={theme}>{children}</ThemeProvider>
        </body>
    </html>
);

export default RootLayout;

এভাবে যদি লিখি তাহলে রেন্ডার হবে না। কারণ আগেই বলেছি ক্লায়েন্ট সাইড রেন্ডারিং বুঝাতে অবশ্যই কনটেক্সট ফাইল বা যেখানে আমি কনটেক্সট ব্যবহার করছি তার উপরে use client; লিখতে হবে। এখন আপনি এই লে-আউট ফাইলে যদি use client; লিখে দেন কাজ করবে না। কারণ লে-আউট ফাইল সবসময় সার্ভার সাইড রেন্ডারিং করে। এখান থেকে আপনি ক্লায়েন্ট সাইড কম্পোনেন্ট বা কনটেক্সট রেন্ডার করতে পারবেন না। তাহলে এখন একটাই উপায়। সেটা হলো MUI এর থিম কনটেক্সট এর উপর যদি কোনোভাবে use client; লেখা যায়। কিন্তু সেটা তো আমরা পারবো না। কিন্তু আমরা আরেকটা কাজ করতে পারি। সেটা হলো আলাদা একটা র‍্যাপার কম্পোনেন্ট তৈরি করে লে-আউটকে সেই র‍্যাপার দিয়ে র‍্যাপ করে দেয়া। মাথার উপর দিয়ে যাচ্ছে। চলুন নিচের কোড দেখি। এরপর বুঝে যাবেন। প্রথম app ফোল্ডারের মধ্যে ContextProvider.jsx নামে একটা ফাইল ক্রিয়েট করে নিলাম। এরপর সেখানে MUI এর ThemeProvider ইমপোর্ট করে একটা র‍্যাপার কম্পোনেন্ট বানিয়ে নিলাম।

'use client';

import { CssBaseline, ThemeProvider } from '@mui/material';
import theme from '../themes/theme';

const ContextProvider = ({ children }) => (
    <ThemeProvider theme={theme}>
        <CssBaseline />
        {children}
    </ThemeProvider>
);

export default ContextProvider;

এবার এই কম্পোনেন্টকে দিয়ে আমরা লে-আউট র‍্যাপ করে দিবো।

import ContextProvider from './ContextProvider';

export const metadata = {
    title: 'Booklab',
    description: 'Booklab',
    viewport: 'width=device-width, initial-scale=1',
};

const RootLayout = ({ children }) => (
    <html lang="en">
        <body>
            <ContextProvider>{children}</ContextProvider>
        </body>
    </html>
);

export default RootLayout;

এবার লে-আউটের সকল কনটেন্ট সার্ভার সাইডে রেন্ডার হবে, শুধমাত্র ContextProvider ক্লায়েন্ট সাইডে রেন্ডার হবে। এভাবে যেকোনো প্যাকেজ বা লাইব্রেরির কনটেক্সট প্রোভাইডারকে আলাদাভাবে ক্লায়েন্ট কম্পোনেন্ট বানিয়ে এরপর লে-আউটে ব্যবহার করতে হবে। আর যদি কাস্টম হুক বার কাস্টম কনটেক্সট নিজেই বানান সেক্ষেত্রে ঐ হুক বা কনটেক্সটকে তো নিজেই ক্লায়েন্ট সাইড হুক বা কনটেক্সট করে নিতে পারছেন।

আশা করছি যারা এই ঝামেলায় পড়েছেন এবং এখনও বুঝে উঠতে পারছেন না কিভাবে কি করবেন তাদের জন্য এই আর্টিকেলটা অনেক উপকার করবে।