কিভাবে CommonJS আপনার বান্ডিলগুলিকে বড় করে তুলছে

কমনজেএস মডিউলগুলি কীভাবে আপনার অ্যাপ্লিকেশনের গাছ-কাঁপানোকে প্রভাবিত করছে তা জানুন

এই পোস্টে, আমরা কমনজেএস কী এবং কেন এটি আপনার জাভাস্ক্রিপ্ট বান্ডিলকে প্রয়োজনের চেয়ে বড় করে তুলছে তা দেখব।

সারাংশ: বান্ডলার আপনার অ্যাপ্লিকেশনটিকে সফলভাবে অপ্টিমাইজ করতে পারে তা নিশ্চিত করতে, CommonJS মডিউলের উপর নির্ভর করে এড়িয়ে চলুন এবং আপনার সম্পূর্ণ অ্যাপ্লিকেশনে ECMAScript মডিউল সিনট্যাক্স ব্যবহার করুন।

CommonJS কি?

CommonJS হল 2009 থেকে একটি স্ট্যান্ডার্ড যা জাভাস্ক্রিপ্ট মডিউলগুলির জন্য নিয়ম প্রতিষ্ঠা করেছে। এটি প্রাথমিকভাবে ওয়েব ব্রাউজারের বাইরে ব্যবহারের উদ্দেশ্যে তৈরি করা হয়েছিল, প্রাথমিকভাবে সার্ভার-সাইড অ্যাপ্লিকেশনগুলির জন্য।

CommonJS এর ​​মাধ্যমে আপনি মডিউল সংজ্ঞায়িত করতে পারেন, তাদের থেকে কার্যকারিতা রপ্তানি করতে পারেন এবং অন্যান্য মডিউলগুলিতে আমদানি করতে পারেন। উদাহরণস্বরূপ, নীচের স্নিপেটটি একটি মডিউলকে সংজ্ঞায়িত করে যা পাঁচটি ফাংশন রপ্তানি করে: add , subtract , multiply , divide এবং max :

// utils.js
const { maxBy } = require('lodash-es');
const fns = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
  multiply: (a, b) => a * b,
  divide: (a, b) => a / b,
  max: arr => maxBy(arr)
};

Object.keys(fns).forEach(fnName => module.exports[fnName] = fns[fnName]);

পরবর্তীতে, অন্য মডিউল আমদানি করতে পারে এবং এই ফাংশনগুলির কিছু বা সমস্ত ব্যবহার করতে পারে:

// index.js
const { add } = require('./utils.js');
console.log(add(1, 2));

node সহ index.js আহ্বান করলে কনসোলে 3 নম্বর আউটপুট হবে।

2010 এর দশকের গোড়ার দিকে ব্রাউজারে একটি প্রমিত মডিউল সিস্টেমের অভাবের কারণে, কমনজেএস জাভাস্ক্রিপ্ট ক্লায়েন্ট-সাইড লাইব্রেরির জন্যও একটি জনপ্রিয় মডিউল ফর্ম্যাটে পরিণত হয়েছিল।

কিভাবে CommonJS আপনার চূড়ান্ত বান্ডিল আকার প্রভাবিত করে?

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

জাভাস্ক্রিপ্ট বান্ডলার এবং মিনিফায়ার, যেমন webpack এবং terser , আপনার অ্যাপের আকার কমাতে বিভিন্ন অপ্টিমাইজেশন সঞ্চালন করে। বিল্ড টাইমে আপনার অ্যাপ্লিকেশন বিশ্লেষণ করে, তারা আপনি যে সোর্স কোড ব্যবহার করছেন না তা থেকে যতটা সম্ভব অপসারণ করার চেষ্টা করে।

উদাহরণস্বরূপ, উপরের স্নিপেটে, আপনার চূড়ান্ত বান্ডেলে শুধুমাত্র add ফাংশন অন্তর্ভুক্ত করা উচিত কারণ এটিই utils.js থেকে একমাত্র প্রতীক যা আপনি index.js এ আমদানি করেন।

আসুন নিম্নলিখিত webpack কনফিগারেশন ব্যবহার করে অ্যাপটি তৈরি করি:

const path = require('path');
module.exports = {
  entry: 'index.js',
  output: {
    filename: 'out.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'production',
};

এখানে আমরা উল্লেখ করছি যে আমরা প্রোডাকশন মোড অপ্টিমাইজেশান ব্যবহার করতে চাই এবং একটি এন্ট্রি পয়েন্ট হিসাবে index.js ব্যবহার করতে চাই। webpack চালু করার পরে, যদি আমরা আউটপুট আকারটি অন্বেষণ করি, আমরা এরকম কিছু দেখতে পাব:

$ cd dist && ls -lah
625K Apr 13 13:04 out.js

লক্ষ্য করুন যে বান্ডিলটি 625KB । আমরা যদি আউটপুটটি দেখি, আমরা utils.js থেকে সমস্ত ফাংশন এবং lodash থেকে অনেক মডিউল খুঁজে পাব । যদিও আমরা index.jslodash ব্যবহার করি না এটি আউটপুটের অংশ , যা আমাদের উৎপাদন সম্পদে অনেক অতিরিক্ত ওজন যোগ করে।

এখন আসুন মডিউল ফরম্যাটটিকে ECMAScript মডিউলে পরিবর্তন করে আবার চেষ্টা করি। এই সময়, utils.js দেখতে এইরকম হবে:

export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export const multiply = (a, b) => a * b;
export const divide = (a, b) => a / b;

import { maxBy } from 'lodash-es';

export const max = arr => maxBy(arr);

এবং index.js ECMAScript মডিউল সিনট্যাক্স ব্যবহার করে utils.js থেকে আমদানি করবে:

import { add } from './utils.js';

console.log(add(1, 2));

একই webpack কনফিগারেশন ব্যবহার করে, আমরা আমাদের অ্যাপ্লিকেশন তৈরি করতে এবং আউটপুট ফাইল খুলতে পারি। এটি এখন নিম্নলিখিত আউটপুট সহ 40 বাইট:

(()=>{"use strict";console.log(1+2)})();

লক্ষ্য করুন যে চূড়ান্ত বান্ডেলে utils.js এর কোনো ফাংশন নেই যা আমরা ব্যবহার করি না এবং lodash থেকে কোনো ট্রেস নেই! এমনকি আরও, terser (জাভাস্ক্রিপ্ট মিনিফায়ার যা webpack ব্যবহার করে) console.logadd ফাংশন ইনলাইন করে।

একটি ন্যায্য প্রশ্ন আপনি জিজ্ঞাসা করতে পারেন, কেন CommonJS ব্যবহার করার ফলে আউটপুট বান্ডিল প্রায় 16,000 গুণ বড় হয় ? অবশ্যই, এটি একটি খেলনা উদাহরণ, বাস্তবে, আকারের পার্থক্যটি এত বড় নাও হতে পারে, তবে কমনজেএস আপনার উত্পাদন বিল্ডে উল্লেখযোগ্য ওজন যুক্ত করার সম্ভাবনা রয়েছে।

CommonJS মডিউলগুলি সাধারণ ক্ষেত্রে অপ্টিমাইজ করা কঠিন কারণ তারা ES মডিউলগুলির তুলনায় অনেক বেশি গতিশীল। আপনার বান্ডলার এবং মিনিফায়ার সফলভাবে আপনার অ্যাপ্লিকেশন অপ্টিমাইজ করতে পারে তা নিশ্চিত করতে, CommonJS মডিউলের উপর নির্ভর করে এড়িয়ে চলুন এবং আপনার সম্পূর্ণ অ্যাপ্লিকেশনে ECMAScript মডিউল সিনট্যাক্স ব্যবহার করুন।

লক্ষ্য করুন যে আপনি index.js এ ECMAScript মডিউল ব্যবহার করলেও, আপনি যে মডিউলটি ব্যবহার করছেন সেটি যদি CommonJS মডিউল হয়, তাহলে আপনার অ্যাপের বান্ডেলের আকার ক্ষতিগ্রস্ত হবে।

CommonJS কেন আপনার অ্যাপকে বড় করে?

এই প্রশ্নের উত্তর দিতে, আমরা webpack ModuleConcatenationPlugin এর আচরণ দেখব এবং তারপরে, স্থির বিশ্লেষণযোগ্যতা নিয়ে আলোচনা করব। এই প্লাগইনটি আপনার সমস্ত মডিউলের সুযোগকে এক বন্ধ করে দেয় এবং ব্রাউজারে আপনার কোডটি দ্রুত কার্যকর করার জন্য অনুমতি দেয়। আসুন একটি উদাহরণ দেখি:

// utils.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
// index.js
import { add } from './utils.js';
const subtract = (a, b) => a - b;

console.log(add(1, 2));

উপরে, আমাদের একটি ECMAScript মডিউল আছে, যা আমরা index.js এ আমদানি করি। আমরা একটি subtract ফাংশন সংজ্ঞায়িত. আমরা উপরের মত একই webpack কনফিগারেশন ব্যবহার করে প্রকল্পটি তৈরি করতে পারি, কিন্তু এইবার, আমরা মিনিমাইজেশন অক্ষম করব:

const path = require('path');

module.exports = {
  entry: 'index.js',
  output: {
    filename: 'out.js',
    path: path.resolve(__dirname, 'dist'),
  },
  optimization: {
    minimize: false
  },
  mode: 'production',
};

আসুন উত্পাদিত আউটপুট দেখি:

/******/ (() => { // webpackBootstrap
/******/    "use strict";

// CONCATENATED MODULE: ./utils.js**
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;

// CONCATENATED MODULE: ./index.js**
const index_subtract = (a, b) => a - b;**
console.log(add(1, 2));**

/******/ })();

উপরের আউটপুটে, সমস্ত ফাংশন একই নামস্থানের ভিতরে রয়েছে। সংঘর্ষ প্রতিরোধ করার জন্য, ওয়েবপ্যাক index.jssubtract ফাংশনের নাম পরিবর্তন করে index_subtract করেছে।

যদি একটি মিনিফায়ার উপরের সোর্স কোডটি প্রক্রিয়া করে, তাহলে এটি হবে:

  • অব্যবহৃত ফাংশন subtract এবং index_subtract সরান
  • সমস্ত মন্তব্য এবং অপ্রয়োজনীয় সাদা স্থান সরান
  • console.log কলে add ফাংশনের বডি ইনলাইন করুন

প্রায়শই বিকাশকারীরা অব্যবহৃত আমদানির এই অপসারণকে গাছ-কাঁপানো হিসাবে উল্লেখ করে। ট্রি-কাঁপানো কেবলমাত্র সম্ভব ছিল কারণ ওয়েবপ্যাক স্থিরভাবে (নির্মাণের সময়) বুঝতে সক্ষম হয়েছিল যে আমরা utils.js থেকে কোন প্রতীকগুলি আমদানি করছি এবং এটি কোন প্রতীকগুলি রপ্তানি করে৷

এই আচরণটি ES মডিউলগুলির জন্য ডিফল্টরূপে সক্রিয় করা হয়েছে কারণ সেগুলি CommonJS-এর তুলনায় আরও স্ট্যাটিকভাবে বিশ্লেষণযোগ্য

আসুন আমরা ঠিক একই উদাহরণটি দেখি, তবে এবার ES মডিউলের পরিবর্তে CommonJS ব্যবহার করতে utils.js পরিবর্তন করুন:

// utils.js
const { maxBy } = require('lodash-es');

const fns = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b,
  multiply: (a, b) => a * b,
  divide: (a, b) => a / b,
  max: arr => maxBy(arr)
};

Object.keys(fns).forEach(fnName => module.exports[fnName] = fns[fnName]);

এই ছোট আপডেট উল্লেখযোগ্যভাবে আউটপুট পরিবর্তন হবে. যেহেতু এই পৃষ্ঠায় এম্বেড করার জন্য এটি খুব দীর্ঘ, আমি এটির একটি ছোট অংশ ভাগ করেছি:

...
(() => {

"use strict";
/* harmony import */ var _utils__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(288);
const subtract = (a, b) => a - b;
console.log((0,_utils__WEBPACK_IMPORTED_MODULE_0__/* .add */ .IH)(1, 2));

})();

লক্ষ্য করুন যে চূড়ান্ত বান্ডেলে কিছু webpack "রানটাইম" রয়েছে: ইনজেক্টেড কোড যা বান্ডেল করা মডিউল থেকে কার্যকারিতা আমদানি/রপ্তানি করার জন্য দায়ী। এইবার, utils.js এবং index.js থেকে সমস্ত চিহ্ন একই নামস্থানে রাখার পরিবর্তে, আমাদের গতিশীলভাবে, রানটাইমে, __webpack_require__ ব্যবহার করে add ফাংশন প্রয়োজন।

এটি প্রয়োজনীয় কারণ CommonJS এর ​​সাথে আমরা একটি নির্বিচারে এক্সপ্রেশন থেকে এক্সপোর্ট নাম পেতে পারি। উদাহরণস্বরূপ, নীচের কোডটি একটি সম্পূর্ণ বৈধ নির্মাণ:

module.exports[localStorage.getItem(Math.random())] = () => { … };

বিল্ড-টাইমে বান্ডলারের জন্য রপ্তানি করা প্রতীকটির নাম কী তা জানার কোনও উপায় নেই কারণ এটির জন্য ব্যবহারকারীর ব্রাউজারের প্রসঙ্গে শুধুমাত্র রানটাইমে উপলব্ধ তথ্যের প্রয়োজন।

এইভাবে, মিনিফায়ার বুঝতে অক্ষম যে index.js তার নির্ভরতা থেকে ঠিক কী ব্যবহার করে তাই এটি গাছ-ঝাঁকিয়ে ফেলতে পারে না। আমরা তৃতীয় পক্ষের মডিউলগুলির জন্যও একই আচরণ পর্যবেক্ষণ করব। যদি আমরা node_modules থেকে একটি CommonJS মডিউল আমদানি করি, তাহলে আপনার বিল্ড টুলচেন এটিকে সঠিকভাবে অপ্টিমাইজ করতে সক্ষম হবে না।

CommonJS এর ​​সাথে গাছ কাঁপানো

CommonJS মডিউল বিশ্লেষণ করা অনেক কঠিন যেহেতু তারা সংজ্ঞা অনুসারে গতিশীল। উদাহরণস্বরূপ, ES মডিউলগুলিতে আমদানি অবস্থান সর্বদা একটি স্ট্রিং আক্ষরিক, CommonJS এর ​​তুলনায়, যেখানে এটি একটি অভিব্যক্তি।

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

উপসংহার

বান্ডলার আপনার অ্যাপ্লিকেশনটিকে সফলভাবে অপ্টিমাইজ করতে পারে তা নিশ্চিত করতে, CommonJS মডিউলের উপর নির্ভর করে এড়িয়ে চলুন এবং আপনার সম্পূর্ণ অ্যাপ্লিকেশনে ECMAScript মডিউল সিনট্যাক্স ব্যবহার করুন।

আপনি সর্বোত্তম পথে আছেন তা যাচাই করার জন্য এখানে কয়েকটি কার্যকরী টিপস রয়েছে:

  • Rollup.js এর নোড-সমাধান প্লাগইন ব্যবহার করুন এবং আপনি শুধুমাত্র ECMAScript মডিউলের উপর নির্ভর করতে চান তা নির্দিষ্ট করতে শুধুমাত্র modulesOnly পতাকা সেট করুন।
  • একটি npm প্যাকেজ ECMAScript মডিউল ব্যবহার করে তা যাচাই করতে প্যাকেজ is-esm ব্যবহার করুন।
  • আপনি যদি কৌণিক ব্যবহার করেন তবে ডিফল্টরূপে আপনি একটি সতর্কতা পাবেন যদি আপনি অ-ট্রি-শেকযোগ্য মডিউলের উপর নির্ভর করেন।