Tree Shaking — অ্যাপ্লিকেশন বিল্ড পর্যায়ে অব্যবহৃত কোড অপসারণের (dead code elimination) একটি প্রক্রিয়া। Tree Shaking ES-মডিউলগুলির স্থির কাঠামো বিশ্লেষণ করে এবং সেই এক্সপোর্ট করা ফাংশন, ক্লাস এবং ভেরিয়েবলগুলি বাদ দেয় যা কোথাও ইম্পোর্ট করা হয়নি। Webpack Documentation অনুসারে, Tree Shaking-এর সঠিক কনফিগারেশন অ্যাপ্লিকেশনের কার্যকারিতা পরিবর্তন না করে বান্ডেলের আকার 30–60% কমাতে পারে।
মূল বিষয়
Tree Shaking একটি কোড অপ্টিমাইজেশন কৌশল যা চূড়ান্ত বান্ডেল থেকে অব্যবহৃত মডিউল এবং ফাংশন বাদ দেয়। শব্দটি Rollup টিম 2015 সালে প্রবর্তন করে এবং রূপকভাবে প্রক্রিয়াটি বর্ণনা করে: নির্ভরতা গাছটি ঝাঁকানো হয়, এবং অব্যবহৃত শাখাগুলি পড়ে যায়। ম্যানুয়াল অপ্টিমাইজেশনের বিপরীতে, Tree Shaking বিল্ড পর্যায়ে স্বয়ংক্রিয়ভাবে সম্পাদিত হয়।
Tree Shaking শুধুমাত্র ES-মডিউল (ECMAScript Modules) এর সাথে কাজ করে, যেখানে নির্ভরতাগুলি import এবং export-এর মাধ্যমে স্থিরভাবে নির্ধারিত হয়। CommonJS (require/module.exports) Tree Shaking সমর্থন করে না কারণ require গতিশীলভাবে সম্পাদিত হয় — বান্ডেলার আগে থেকে নির্ধারণ করতে পারে না কোন ফাংশনগুলি আসলে ব্যবহৃত হয়। আধুনিক লাইব্রেরি (Lodash, Moment.js, RxJS) Tree Shaking সমর্থনের জন্য ES সংস্করণ প্রকাশ করে।
Rollup প্রথম বান্ডেলার যা 2015 সালে Tree Shaking বাস্তবায়ন করে। Webpack-এর বিপরীতে, Rollup প্রথম থেকেই ES-মডিউলের জন্য ডিজাইন করা হয়েছিল এবং আরও আক্রমণাত্মক মৃত কোড অপসারণ executes। Rollup শুধুমাত্র পৃথক এক্সপোর্ট নয় বরং সম্পূর্ণ মডিউল বিশ্লেষণ করে: যদি একটি মডিউলের কোনো পার্শ্ব প্রতিক্রিয়া না থাকে এবং কোনো এক্সপোর্ট ব্যবহার না করা হয়, Rollup সম্পূর্ণ মডিউলটি বান্ডেল থেকে বাদ দেয়।
Rollup বিশেষ করে লাইব্রেরি এবং SDK-এর জন্য কার্যকর যেখানে প্রতিটি কিলোবাইট গুরুত্বপূর্ণ। Vue.js ফ্রেমওয়ার্ক তার প্রোডাকশন সংস্করণ তৈরির জন্য Rollup ব্যবহার করে। React 2020 সালে Rollup-এ স্থানান্তরিত হয়। অ্যাপ্লিকেশনের জন্য, Webpack বেশি সাধারণত ব্যবহৃত হয় এর সমৃদ্ধ প্লাগইন ইকোসিস্টেমের (Hot Module Replacement, code splitting, CSS modules) কারণে, কিন্তু লাইব্রেরি তৈরি করার সময় সর্বোচ্চ Tree Shaking-এর জন্য, Rollup শিল্পের মান হিসাবে রয়ে গেছে।
Tree Shaking থেকে সাশ্রয় প্রকল্পের আর্কিটেকচারের উপর strongly নির্ভর করে। Ant Design লাইব্রেরি সহ একটি React অ্যাপ্লিকেশনে, Tree Shaking UI কম্পোনেন্টের 70% পর্যন্ত কোড অপসারণ করতে পারে। একটি প্রকল্পে যেখানে সমস্ত ইম্পোর্ট নির্দিষ্ট এবং টার্গেটেড, সাশ্রয় হবে 5–15%। Webpack গবেষণা অনুসারে, গড় সাশ্রয় বান্ডেল আকারের 30–40%।
| মৃত কোডের ধরন | উদাহরণ | Tree Shaking সনাক্তকরণ |
|---|---|---|
| অব্যবহৃত এক্সপোর্ট | export function unusedHelper() | হ্যাঁ |
| অব্যবহৃত ইম্পোর্ট | import { unused } from "lib" | হ্যাঁ |
| মৃত শর্ত শাখা | if (false) { ... } | না (মিনিফায়ার দ্বারা অপসারিত) |
| DCE-এর পরে অকল করা ফাংশন | function a(){} a() যেখানে a কল করা হয়নি | আংশিকভাবে |
Tree Shaking প্রক্রিয়া একটি নির্ভরতা গ্রাফের উপর ভিত্তি করে যা বান্ডেলার প্রকল্পের সমস্ত import/export স্টেটমেন্ট থেকে তৈরি করে। প্রথম ধাপে, বান্ডেলার এন্ট্রি পয়েন্ট থেকে সমস্ত ফাইল ট্রাভার্স করে এবং মডিউল ট্রি সংগ্রহ করে। দ্বিতীয় ধাপে, এটি বিশ্লেষণ করে প্রতিটি মডিউল থেকে কোন এক্সপোর্টগুলি আসলে অন্যান্য মডিউলে ইম্পোর্ট করা হয়েছে।
প্রতিটি মডিউলের জন্য, Webpack বা Rollup এক্সপোর্টগুলি ব্যবহৃত বা অব্যবহৃত হিসাবে চিহ্নিত করে। অব্যবহৃত এক্সপোর্টগুলি বান্ডেল থেকে বাদ দেওয়া হয়। তবে, মডিউলটি নিজেই বান্ডেলে থাকে যদি এর অন্তত একটি এক্সপোর্ট ব্যবহৃত হয়। একটি মডিউল সম্পূর্ণরূপে বাদ দেওয়া যেতে পারে শুধুমাত্র sideEffects ফ্ল্যাগের মাধ্যমে বা যদি মডিউলে কোনো পার্শ্ব প্রতিক্রিয়া না থাকে।
// utils.js — ফাংশন সহ মডিউল
export function formatDate(date) {
return date.toISOString().slice(0, 10);
}
export function formatCurrency(amount) {
return "$" + amount.toFixed(2);
}
export function slugify(text) {
return text.toLowerCase().replace(/\s+/g, "-");
}// app.js — এন্ট্রি পয়েন্ট
import { formatDate } from "./utils";
const today = formatDate(new Date());
console.log(today);// Tree Shaking-এর পরে — বান্ডেলে শুধুমাত্র formatDate
function formatDate(date) {
return date.toISOString().slice(0, 10);
}
const today = formatDate(new Date());
console.log(today);Tree Shaking চূড়ান্ত বান্ডেল থেকে formatCurrency এবং slugify বাদ দিয়েছে কারণ এগুলি app.js-এ ইম্পোর্ট করা হয়নি। utils.js মডিউলের আকার 3 ফাংশন থেকে 1-এ কমেছে। যদি utils.js-এ পার্শ্ব প্রতিক্রিয়া থাকে (যেমন, গ্লোবাল ইনিশিয়ালাইজেশন), Tree Shaking অব্যবহৃত এক্সপোর্টগুলিও অপসারণ করতে পারে না।
Webpack প্রোডাকশন মোডে TerserPlugin-এর মাধ্যমে বিল্ট-ইন Tree Shaking সমর্থন অন্তর্ভুক্ত করে। Tree Shaking সক্ষম করার জন্য, দুটি শর্ত যথেষ্ট: mode production-এ সেট করা (mode: "production") এবং মডিউলগুলি ES সিনট্যাক্স (import/export) ব্যবহার করে। Webpack স্বয়ংক্রিয়ভাবে অব্যবহৃত এক্সপোর্ট চিহ্নিত করে এবং অপসারণের জন্য Terser-এ পাঠায়।
optimization.webpack.config.js-এ অতিরিক্ত usedExports: true কনফিগারেশন একটি মডিউলের ভিতরে এক্সপোর্ট ব্যবহারের বিস্তারিত বিশ্লেষণ সক্ষম করে। এই বিকল্প নির্ধারণ করে কোন এক্সপোর্টগুলি আসলে ব্যবহৃত হয়েছে এবং কোনটি শুধুমাত্র এক্সপোর্ট করা হয়েছে (provided)। usedExports এবং Terser-এর সংমিশ্রণ সর্বোচ্চ মৃত কোড অপসারণ দক্ষতা দেয়।
// webpack.config.js — Tree Shaking কনফিগারেশন
module.exports = {
mode: "production",
entry: "./src/app.js",
output: {
filename: "bundle.js",
},
optimization: {
usedExports: true,
minimize: true,
concatenateModules: true,
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules\/(?!(my-lib)\/).*/,
use: {
loader: "babel-loader",
options: {
presets: [
["@babel/preset-env", { modules: false }],
],
},
},
},
],
},
};মূল প্যারামিটার হল @babel/preset-env-এ modules: false। ডিফল্টরূপে, Babel ES-মডিউলগুলিকে CommonJS-এ রূপান্তর করে, যা Tree Shaking কে ধ্বংস করে। modules: false Babel-কে import/export রূপান্তর করতে বাধা দেয়, Webpack-এর জন্য ES সিনট্যাক্স সংরক্ষণ করে। concatenateModules অতিরিক্তভাবে মডিউলগুলিকে একটি শেয়ার্ড স্কোপে একত্রিত করে, IIFE-এর সংখ্যা হ্রাস করে এবং বান্ডেল আকার কমায়।
Side effects (পার্শ্ব প্রতিক্রিয়া) — একটি মডিউল ইম্পোর্ট করার সময় সম্পাদিত ক্রিয়া যা এক্সপোর্ট করা মানগুলির সাথে সম্পর্কিত নয়: গ্লোবাল স্টাইল (import "./styles.css"), পলিফিল (import "core-js/stable"), গ্লোবাল ভেরিয়েবল ইনিশিয়ালাইজেশন বা Service Worker রেজিস্ট্রেশন। যদি একটি মডিউলে পার্শ্ব প্রতিক্রিয়া থাকে, বান্ডেলার এটি বান্ডেল থেকে নিরাপদে অপসারণ করতে পারে না, এমনকি যদি এর কোনো এক্সপোর্ট ব্যবহার না করা হয়।
package.json-এ sideEffects ফ্ল্যাগ বান্ডেলারকে জানায় প্যাকেজের কোন মডিউলগুলির কোনো পার্শ্ব প্রতিক্রিয়া নেই। একটি প্যাকেজের জন্য যেখানে সমস্ত মডিউল বিশুদ্ধ (শুধুমাত্র ফাংশন এক্সপোর্ট), "sideEffects": false নির্দিষ্ট করা উচিত। CSS বা পলিফিলযুক্ত প্যাকেজের জন্য — পার্শ্ব প্রতিক্রিয়া সহ ফাইলগুলির পাথের একটি অ্যারে: "sideEffects": ["*.css"]। এই ফ্ল্যাগ ছাড়া, Tree Shaking অব্যবহৃত ফাংশনগুলিও অপসারণ করবে না।
একটি মডিউলে পার্শ্ব প্রতিক্রিয়া আছে কিনা তা পরীক্ষা করতে, এই প্রশ্নটি করুন: এই ইম্পোর্টটি কি মান এক্সপোর্ট করার সাথে সম্পর্কিত নয় এমন কোনো ক্রিয়া সম্পাদন করবে? import "./styles.css" DOM-এ CSS যোগ করে — এটি একটি পার্শ্ব প্রতিক্রিয়া। import { throttle } from "lodash-es"-এর কোনো পার্শ্ব প্রতিক্রিয়া নেই — এটি শুধুমাত্র throttle ফাংশনটি উপলব্ধ করে। পলিফিল (import "core-js/stable")-এর পার্শ্ব প্রতিক্রিয়া আছে — তারা গ্লোবাল প্রোটোটাইপ পরিবর্তন করে।
আপনার নিজস্ব মডিউলের জন্য, সুপারিশ করা হয়: স্টাইল এবং পলিফিল আলাদা এন্ট্রি পয়েন্টে বের করুন, বিশুদ্ধ ইউটিলিটি (পার্শ্ব প্রতিক্রিয়া ছাড়া ফাংশন) এবং পার্শ্ব প্রতিক্রিয়া সহ মডিউল (ইনিশিয়ালাইজেশন, লগিং, Service Worker রেজিস্ট্রেশন) আলাদা করুন। শীর্ষ-স্তরের প্রকল্প package.json-এ, "sideEffects": false শুধুমাত্র তখনই নির্দিষ্ট করুন যদি সমস্ত মডিউল বিশুদ্ধ হয়। যদি স্টাইল থাকে, তবে সঠিকভাবে "sideEffects": ["*.css"] নির্দিষ্ট করুন।
{
"name": "my-ui-lib",
"version": "2.1.0",
"sideEffects": [
"*.css",
"polyfills.js"
],
"module": "dist/index.esm.js",
"main": "dist/index.cjs.js"
}"sideEffects": ["*.css", "polyfills.js"] মানে: সমস্ত CSS ফাইলের পার্শ্ব প্রতিক্রিয়া আছে (এগুলি অপসারণ করা যাবে না) এবং polyfills.js-এরও আছে। প্যাকেজের অন্যান্য সমস্ত JS ফাইল বিশুদ্ধ — এগুলি নিরাপদে shake করা যেতে পারে। module ফিল্ড প্যাকেজের ES সংস্করণের পাথ নির্দিষ্ট করে যা বান্ডেলারকে Tree Shaking-এর জন্য CommonJS সংস্করণ (main) এর পরিবর্তে ব্যবহার করা উচিত।
React Native Metro Bundler-এর সাথে Tree Shaking-এর একটি সীমিত সংস্করণ সমর্থন করে। Metro Webpack-এর মতো ব্যবহৃত এক্সপোর্টগুলির (usedExports) পূর্ণ স্থির বিশ্লেষণ করে না। পরিবর্তে, Metro মিনিফিকেশনের সময় মডিউলের অব্যবহৃত অংশগুলি অপসারণ করতে Terser-এর উপর নির্ভর করে। এই পদ্ধতির কার্যকারিতা Webpack-এর পূর্ণ Tree Shaking-এর চেয়ে কম।
React Native প্রকল্পের সর্বোচ্চ অপ্টিমাইজেশনের জন্য, সুপারিশ করা হয়: ES-মডিউল সহ লাইব্রেরি ব্যবহার করুন (package.json-এ module ফিল্ড), ডিবাগ কোড অপসারণের জন্য babel-plugin-transform-remove-console যোগ করুন এবং Terser-এর জন্য Metro transformer.minifierConfig কনফিগার করুন। অতিরিক্তভাবে, Ram Bundle (বান্ডেলকে মডিউলে বিভক্ত করা) অব্যবহৃত স্ক্রিনের লোডিং হ্রাস করে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
CommonJS (require/module.exports) স্থির বিশ্লেষণ সমর্থন করে না — require শর্ত এবং ফাংশনের ভিতরে গতিশীলভাবে কল করা যেতে পারে। বান্ডেলার নির্ধারণ করতে পারে না মডিউলের কোন অংশগুলি আসলে ব্যবহৃত হয়। শুধুমাত্র স্থির import/export সহ ES-মডিউল Tree Shaking সক্ষম করে।
TypeScript Tree Shaking-এর সাথে সম্পূর্ণ সামঞ্জস্যপূর্ণ যদি tsconfig.json ES-মডিউলের জন্য কনফিগার করা থাকে: "module": "esnext"। TypeScript কম্পাইলারকে import/export CommonJS-এ রূপান্তর না করে সংরক্ষণ করতে হবে। @babel/preset-typescript এবং modules: false সহ Babel-ও ES-মডিউল Webpack-এ সঠিকভাবে পাঠায়।
Webpack Bundle Analyzer — একটি প্লাগইন যা বান্ডেলের গঠনকে একটি ইন্টারেক্টিভ ডায়াগ্রাম হিসাবে ভিজুয়ালাইজ করে। যদি একটি লাইব্রেরি বান্ডেলে উপস্থিত থাকে কিন্তু তার ফাংশনগুলি ব্যবহার না করা হয়, Tree Shaking কাজ করেনি। আপনি আউটপুট ফাইলও বিশ্লেষণ করতে পারেন: grep-এর মাধ্যমে বান্ডেল টেক্সটে অব্যবহৃত এক্সপোর্ট খুঁজুন।
Lodash v4 একটি CommonJS প্যাকেজ হিসাবে বিতরণ করা হয়। Tree Shaking-এর জন্য, আপনাকে lodash-es — লাইব্রেরির ES সংস্করণ — ব্যবহার করতে হবে। import throttle from "lodash/throttle"-কে import { throttle } from "lodash-es" দিয়ে প্রতিস্থাপন করুন এবং lodash-কে lodash-es দিয়ে প্রতিস্থাপন করতে Webpack-এ resolve.alias কনফিগার করুন।
Tree Shaking বিল্ড সময় সামান্য বাড়ায় (5–15% দ্বারা) কারণ এটি নির্ভরতা গ্রাফ বিশ্লেষণ এবং ব্যবহৃত এক্সপোর্ট চিহ্নিত করার ধাপ যোগ করে। ডেভেলপমেন্ট মোডে, Tree Shaking সাধারণত গতির জন্য নিষ্ক্রিয় করা হয়। প্রোডাকশনে, অতিরিক্ত সময় বান্ডেল আকারে উল্লেখযোগ্য হ্রাস দ্বারা ন্যায়সঙ্গত।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন