JavaScript Modules & Bundlers

"Divide and Conquer"

কল্পনা করো একটি লাইব্রেরির কথা যেখানে ১ লাখ বই আছে, কিন্তু কোনো তাক বা বিভাগ নেই। সব বই ফ্লোরে স্তূপ করে রাখা। তুমি কি কোনো বই খুঁজে পাবে? অসম্ভব!

কোডিংয়েও তাই। সব কোড এক ফাইলে (script.js) লিখলে সেটা মেইনটেইন করা নরক যন্ত্রণার মতো। Modules আমাদের কোডকে ছোট ছোট, স্বাধীন ফাইলে ভাগ করার সুযোগ দেয়।

⭐ ১. ইতিহাস: CommonJS vs ES Modules (ESM)

জাভাস্ক্রিপ্টে মডিউলের ইতিহাস দুই ভাগে বিভক্ত।

A) CommonJS (The Old King of Node.js) 👴

Node.js যখন এল, তখন জাভাস্ক্রিপ্টে অফিশিয়াল মডিউল সিস্টেম ছিল না। তাই তারা require এবং module.exports চালু করে।

বৈশিষ্ট্য: Synchronous (একটার পর একটা লোড হয়), সার্ভারের জন্য ভালো, ব্রাউজারের জন্য স্লো।

// utils.js
const sum = (a, b) => a + b;
module.exports = { sum }; // Export

// app.js
const { sum } = require('./utils'); // Import

B) ES Modules (The Modern Standard) 🚀

২০১৫ সালে (ES6) জাভাস্ক্রিপ্ট অফিশিয়াল মডিউল সিস্টেম পায়। এখন ব্রাউজার, মডার্ন Node.js, React, Vue—সবাই এটা ব্যবহার করে।

বৈশিষ্ট্য: Asynchronous, Tree-shaking সাপোর্ট করে, স্ট্যাটিক এনালাইসিস সম্ভব।

⭐ ২. ES Modules: Named vs Default Exports

জুনিয়ররা প্রায়ই কনফিউজড হয়—কখন {} ব্র্যাকেট দেব, আর কখন দেব না?

A) Named Export (নাম ধরে ডাকা) 📛

যখন এক ফাইল থেকে একাধিক জিনিস এক্সপোর্ট করতে চাও।

// math.js
export const add = (a, b) => a + b;
export const sub = (a, b) => a - b;

// app.js
import { add, sub } from './math.js'; // নাম হুবহু মিলতে হবে

Senior Tip: বড় প্রজেক্টে Named Export ব্যবহার করা ভালো। কারণ এতে VS Code অটো-ইম্পোর্ট সাজেশন ভালো দেয় এবং রিফ্যাক্টর করা সহজ।

B) Default Export (একক রাজা) 👑

যখন ফাইল থেকে প্রধানত একটাই জিনিস এক্সপোর্ট হবে।

// User.js
export default class User { ... }

// app.js
import UserProfile from './User.js'; // নাম যা খুশি দেওয়া যায়, ব্র্যাকেট লাগে না

সীমাবদ্ধতা: এক ফাইলে মাত্র একটি default এক্সপোর্ট থাকতে পারে।

⭐ ৩. Dynamic Imports (Lazy Loading) ⚡

সব কোড অ্যাপ লোড হওয়ার শুরুতেই লোড করার দরকার নেই। ধরো, "Admin Dashboard" এর কোড সাধারণ ইউজারের দরকার নেই। তাহলে কেন লোড করব?

// সাধারণ import (শুরুতেই লোড হয়)
// import { heavyChart } from './chart.js';

button.addEventListener('click', async () => {
    // Dynamic Import (বাটনে ক্লিক করলেই কেবল ডাউনলোড হবে)
    const module = await import('./chart.js');
    module.heavyChart.render();
});

React/Next.js এ একেই Code Splitting বলা হয়।

⭐ ৪. Barrel Pattern (Clean Architecture) 🗂️

বড় প্রজেক্টে ইম্পোর্ট লাইনগুলো দেখতে বিশ্রী হয়ে যায়।

❌ Messy:

import { Button } from './components/Button';
import { Card } from './components/Card';
import { Input } from './components/Input';

✅ Senior Way (Barrel File):

আমরা ফোল্ডারের ভেতর একটা index.js বানাই যা সব এক্সপোর্টকে এক করে দেয়।

// components/index.js (The Barrel)
export * from './Button';
export * from './Card';
export * from './Input';

// app.js
import { Button, Card, Input } from './components'; // এক লাইন!

⭐ ৫. Tree Shaking: কোড ঝেড়ে ফেলা 🌳

এটি একটি অ্যাডভান্সড কনসেপ্ট। তুমি একটা লাইব্রেরি (Lodash) ইম্পোর্ট করলে যার সাইজ 100KB, কিন্তু ব্যবহার করলে মাত্র ১টি ফাংশন। বাকি কোড কি ইউজারের ব্রাউজারে যাবে?

  • CommonJS: হ্যাঁ, পুরো লাইব্রেরি লোড হবে। ❌
  • ES Modules: না! Webpack বা Vite বুঝতে পারে কোন অংশটা ব্যবহার হয়নি। সে "গাছ ঝাঁকি দেয়" (Tree Shake) এবং মরা পাতাগুলো (Unused Code) ফেলে দেয়।
// utils.js
export const used = () => console.log("I am used");
export const unused = () => console.log("I am dead code");

// app.js
import { used } from './utils';
used();

// ফাইনাল বান্ডিলে unused ফাংশনটি থাকবেই না!

⭐ ৬. Node.js এ ES Modules ব্যবহার

আগে Node.js শুধু CommonJS বুঝত। এখন তুমি দুইভাবে ESM ব্যবহার করতে পারো:

  • ফাইলের এক্সটেনশন .mjs দিয়ে
  • package.json ফাইলে "type": "module" লিখে

🧠 ৭. Senior Interview Questions

Q1: require এবং import এর মূল পার্থক্য কী?

উত্তর:
• require হলো Synchronous (ব্লকিং), import হলো Asynchronous
• require রানটাইমে কাজ করে (কোড চলার সময়), import কম্পাইল টাইমে কাজ করে (কোড চলার আগে)। এজন্যই import দিয়ে Tree Shaking সম্ভব।

Q2: Circular Dependency কী এবং কিভাবে এড়ানো যায়?

উত্তর: ফাইল A ইম্পোর্ট করে B কে, আবার B ইম্পোর্ট করে A কে। এটা লুপ তৈরি করে এবং অ্যাপ ক্র্যাশ বা undefined এরর দিতে পারে।
সমাধান: কোড স্ট্রাকচার ঠিক করা বা উভয় লজিককে তৃতীয় একটি ফাইলে (C) নিয়ে যাওয়া।

Q3: কেন লাইব্রেরি বানানোর সময় Default Export এড়িয়ে চলতে বলা হয়?

উত্তর: কারণ Named Export ব্যবহারকারীকে বাধ্য করে সঠিক নাম ব্যবহার করতে। Default Export এ নাম যা খুশি দেওয়া যায়, ফলে একেক ফাইলে একেক নাম দিলে কোডবেস অগোছালো হয়ে যায়।

Q4: Live Bindings কী? (ESM Speciality)

উত্তর: CommonJS ভ্যালুর কপি পাঠায়, কিন্তু ESM ভ্যালুর Reference পাঠায়। অর্থাৎ, এক্সপোর্ট করা ফাইলের ভ্যালু বদলালে, ইম্পোর্ট করা ফাইলে অটোমেটিক সেটা আপডেট হয়ে যায়।

📊 CommonJS vs ES Modules Comparison

Feature CommonJS ES Modules
Syntax require / module.exports import / export
Loading Synchronous Asynchronous
Tree Shaking ❌ Not Supported ✅ Supported
Environment Node.js (Legacy) Modern Browsers + Node.js
Live Binding ❌ (Copies value) ✅ (References value)

🚀 অধ্যায় ১৬ সারাংশ (Checklist)

আমরা শিখলাম:

  • System: ব্রাউজারের জন্য ESM (import/export) ইজ স্ট্যান্ডার্ড
  • Organization: Barrel Pattern (index.js) দিয়ে ইম্পোর্ট ক্লিন রাখা
  • Optimization: Named Export ব্যবহার করলে Tree Shaking ভালো কাজ করে
  • Performance: Dynamic Import দিয়ে অ্যাপের ইনিশিয়াল লোড টাইম কমানো
  • Tools: Webpack বা Vite এর মতো বান্ডলাররা মডিউলগুলোকে জোড়া লাগিয়ে ব্রাউজারের জন্য অপটিমাইজড ফাইল বানায়

Next Step: আমরা কোড স্ট্রাকচার শিখেছি। কিন্তু জাভাস্ক্রিপ্ট ইঞ্জিন (V8) আসলে কিভাবে এই কোড রান করে? মেমোরি লিক কেন হয়? পরের অধ্যায়: "Event Loop Deep Dive & Internals"।

🔒 কপিরাইট সুরক্ষিত কন্টেন্ট 🔒

কপি, স্ক্রিনশট, প্রিন্ট করা সম্পূর্ণ নিষিদ্ধ।