navidkhm
navidkhm
خواندن ۴ دقیقه·۱ سال پیش

تفاوت require و import در JS یا مختصری از ماژول سیستم‌ها در JS

آقا من تلاش کردم که تا جای ممکن فارسی بنویسم و فکر کنم تو عنوان جالب نشده پس سریع انگلیسیشو میگم که جا بیوفته.

منظورم از ماژول سیستم‌ها همون Module System هستش که احتمالا میدونید چیه فقط شاید به این اسم نمیدونید و الان میگم.

CJS vs ESM in JS
CJS vs ESM in JS

ماژول و ماژول سیستم در JS

اینکه من بخوام منطق‌هامو بشکنم و چندتا فایل کنم و بعد یه فایلی رو توی یه فایل دیگه بیارم ازش استفاده کنم میگیم ماژول و در JS به‌خاطر اینکه در طول زمان تغییرات داشته و یکپارچه هم نبوده(مثل پایتون نبوده مثلا یه تیم پشتش باشه ورژن بده) ما چند روش داریم برای اینکه ماژول‌هامون رو تو یه فایل وارد کنیم(فراخوانی میگیم بهش) که دو تا از مهم‌ترین سینتکس‌هاش همون Require و import هستن که در واقع require نماینده CJS(Common JS) و import نماینده (ECMAScript Module)ESM.

اون اوایل که تازه میخواستن از ماژول استفاده کنن سریع راه‌حلی که دادن این بود که require استفاده کنیم و در واقع گویا Node.js هم این راه‌‌حلو داد و بهش گفتن CommonJS و بعدها هم ECMAScript راه حل دیگه‌ای داد که یکم بهتر بود و اسمش شد ECMAScript Module که مرسوم‌تره و با همون import استفاده می‌کنیم ازش و یکی از مهم‌ترین فرقاشون اینه که require وایمیسه که کل فایل لود بشه (در واقع Synchronous هستش) و بعد میره خط بعدی اما import اینطوری نیستش و میتونه همزمان کدای فایل اصلی رو اجرا کنه و وقتی اون ماژولی که فراخونده بود لود شد اونم بیاره تو بازی که خب طبیعتا سریعتره.

پسوندهای هر کدوم هم اینطوریه:

  • CJS --> .cjs
  • ESM --> .mjs

این دوتا البته مرسوم‌ترین ها هستن و انواع دیگه از جمله AMD, UMD هم داریم که لینک توضیحات مختصر اونا هم پایین اینجا میذارم.

دوپارگی(چندپارگی) مسئله همیشگی در JS

حالا یه نکته مهم اینه که این دو تا سیستم عملا اکوسیستم JS رو دوپاره کرده‌ن و برای پکیج نوشتن دقت کرده باشید معمولا دو نسخه از این دو تا سیستم رو میذارن که هر کس از هر کدوم که داره استفاده میکنه به مشکل نخوره.

مثالی از قرار دادن هر دو شیوه مرسوم ماژول سیستم در پکیج‌ها
مثالی از قرار دادن هر دو شیوه مرسوم ماژول سیستم در پکیج‌ها

نحوه فراخوانی هر یک از ماژول‌ها با ماژول سیستم دیگر

توی ESM خیلی ساده میتونیم فایل .cjs رو فراخوانی کنیم ولی تو CJS چون گفتیم synchronous هست با لطائف‌الحیل باید کاری کنیم تا .mjs فراخوانی شه:

  • Importing ESM(.mjs) into CJS
const example = await import(&quot./example.mjs&quot)
  • Importing CJS(.cjs) into ESM
import example from &quot./example.cjs&quot

در واقع چون برای فراخوانی ESM در CJS به شکل عادی ناتوانیم مجبوریم به جای require از فانکشن import استفاده کنیم و await هم میکنیم تا لود شه و بعد مابقی کد اجرا شه که CJS ناراحت نشه.


ESM یا CJS ؟؟

پیشنهاد میشه که همه از ESM استفاده کنن و یه قرارداد باشه تا کم‌کم کل اکوسیستم به این سمت بره(یکپارچه) و کدهای با استایل سیستم CJS بازنویسی بشن

مسئله باندلرها

امااااا قبلا اگه باندلرهاتون رو بعد از بیلد نگاه کرده بودید میدیدید که شما ماژول رو import کردید ولی خروجی دارید require میبینید(البته بستگی به کانفیگی که مثلا روی وب‌پکتون انجام دادید هم داشت و الخ) که چندان کار جالبی نبود ولی بخاطر پشتیبانی مرورگرا اینکارو میکردن که خیالشون از اجرای کد راحت باشه ولی بعضا میتونه تو فایلای بزرگ توی کارکرد تاثیراتی بذاره اما چون دیگه تقریبا همه مرورگرا ESM رو پشتیبانی میکنن الان کمتر این تغییرو توی بیلد میبینید.

تبدیل import به require بعد از بیلد توسط باندلر
تبدیل import به require بعد از بیلد توسط باندلر


کوفته برنجی و ادعای پاسخ به مسئله‌ی قدیمی

حالا این وسط کوفته‌برنجی پر سروصدا (Bun) هم اومده گفته من این مشکل رو حل کردم و دیگه نگران اینکه ماژولتون ESM هست یا CJS نباشید که اگه واقعا اینکارو کرده باشه بعد از شاید یک‌دهه به این مشکل عجیب پایان داده و دست و جیغ و هورا !!


حالا یه نکته پایانی هم بگم اگه از هر دو نوع ماژول سیستم‌ها برای فراخوانی استفاده کنیم میتونه مشکل‌ساز بشه که بهش میگن Dual Package Hazard :)

Dual Package Hazard یا فراخوانی یک ماژول با دو ماژول سیستم
Dual Package Hazard یا فراخوانی یک ماژول با دو ماژول سیستم


منابع و تشکر :)

ایده‌ی زیبا و توضیح زیباتر این مفاهیم رو بیشتر و در ابتدا از "Matt Pocock" در ویدیویی که لینکش رو میذارم فرا گرفتم و مابقی رو پراکنده از لینک‌هایی که پیدا کردم که اونا هم میذارم.

  1. https://www.youtube.com/watch?v=6_JNPmjSevo
  2. https://adamcoster.com/blog/commonjs-and-esm-importexport-compatibility-examples
  3. جهت مطالعه‌ی مختصر باقی ماژول سیستم‌ها:

https://medium.com/@halilatilla/differences-between-javascript-modules-cjs-amd-umd-and-esm-f60124de131b#:~:text=CommonJS%20(CJS)%3A,and%20provides%20a%20simple%20syntax

ماژول سیستم‌هاimport vs requireimport in jsjsmodule system
شاید از این پست‌ها خوشتان بیاید