اگر اخیراً با ابزارهای جاوا اسکریپت دستکاری کرده اید، احتمالاً با ESM (ECMAScript Modules) مواجه شده اید - روشی استاندارد و بومی برای تقسیم کد به فایل های قابل استفاده مجدد، به جای سر زدن به فراخوانی های قدیمی CommonJS () require. اما نکته اینجاست: اگر مانند ما یک تامین کننده متمرکز بر لودر هستید، می دانید که هر محیطی با ESM خارج از جعبه خوب بازی نمی کند. اینجاست که babel-esm-loader وارد میشود، و امروز من دقیقاً نحوه کارکرد آن را توضیح میدهم، هیچ اصطلاح خفهکنندهای مجاز نیست.
اول، بیایید یک چیز را مستقیم بگوییم: ما در اینجا در مورد ماشین آلات ساختمانی صحبت نمی کنیم، اما اگر می خواهید سطح درک تیم خود را از لودرها در یک صنعت کاملاً متفاوت ارتقا دهید، Skid-steer Loaders را بررسی کنید - آن اسب های کار فشرده که حفاری، بلند کردن و ورود به سایت های کاری تنگ را انجام می دهند. لودرهای ما کمی متفاوت کار می کنند، اما هر دو به یک ایده اصلی خلاصه می شوند: آنها ورودی خام را دریافت می کنند و آن را به چیزی تبدیل می کنند که محیط شما واقعاً می تواند اجرا کند.
حالا به babel-esm-loader برگردیم. بیایید با زمینه شروع کنیم. Babel ابزاری است که برای توسعه دهندگان جاوا اسکریپت به منظور بازنویسی سینتکس جدیدتر (فکر کنید زنجیره اختیاری، خصوصیات کلاس) در کدهایی که مرورگرهای قدیمی یا نسخه های Node قابل درک هستند، استفاده می شود. اما قبل از اینکه babel-esm-loader وجود داشته باشد، اگر سعی میکردید یک فایل ESM را در Node بارگیری کنید، Node کار خودش را انجام میداد، و babel معمولاً فقط به عنوان یک مرحله ساخت جداگانه اجرا میشد - به این معنی که تمام کد خود را یک بار کامپایل میکردید، سپس آن را اجرا میکردید، بدون هیچ تغییری در لحظه. اگر در حال آزمایش هستید، یا اگر زنجیره ابزار شما نیاز به تنظیم کد در پرواز داشته باشد، این یک سردرد است.


Babel-esm-loader این مشکل را با ادغام مستقیم در سیستم ESM Node درست در زمانی که Node در شرف واکشی و پردازش یک ماژول است، برطرف میکند. بیایید گام به گام، نحوه اجرای واقعی آن در پشت صحنه را مرور کنیم:
-
ابتدا لودر را ثبت کنید. حتی قبل از اینکه اسکریپت Node خود را اجرا کنید، باید به Node بگویید: "هی، به جای کنترل کننده ماژول پیش فرض خود از این لودر سفارشی استفاده کن." شما این کار را با یک پرچم انجام می دهید: node --loader babel-esm-loader your-script.js. این پرچم به خط لوله وضوح ماژول Node متصل می شود - Node دارای مجموعه خاصی از قلاب ها است که از آن برای مدیریت وارد کردن ماژول ها استفاده می کند، مانند حل یک مسیر فایل، واکشی محتوای فایل، و تبدیل آن قبل از اجرا. لودر به آن قلاب ها ضربه می زند.
-
قلاب حل: وقتی Node به دنبال یک ماژول میگردد، فقط به دنبال یک فایل .js نمیگردد. واردات package.json، نام ماژول های خالی (مانند 'lodash')، و پسوند فایل ها را بررسی می کند. قلاب حل babel-esm-loader جایی که Node به دنبال فایلها میگردد تغییر نمیکند – فقط مطمئن میشود که هر فایلی که پیدا میکند در صورت نیاز به عنوان یک ماژول ESM علامتگذاری میشود. صبر کنید، نه، تصحیح: اگر یک ماژول پسوند mjs. نداشته باشد، یا package.json آن "type": "module" نداشته باشد، Node ممکن است آن را به عنوان CommonJS در نظر بگیرد. این قلاب این را تنظیم می کند: اگر لودر فعال باشد، می تواند ماژول را به عنوان ESM علامت گذاری کند، حتی اگر یک فایل js.
-
قلاب بار: جادوی واقعی اینجاست. هنگامی که Node مسیر فایل را پیدا کرد، محتوای فایل را واکشی می کند. قلاب بارگذاری پیشفرض Node فقط متن خام را برمیگرداند، اما قلاب بارگذاری babel-esm-loader آن کد خام را میگیرد، آن را از طریق Babel اجرا میکند و کد تبدیلشده را به عنوان ESM برمیگرداند. بیایید آن را عینی کنیم: فرض کنید یک فایل با کدی مانند const add = (a, b) => a + b دارید. صادرات به طور پیش فرض افزودن; — اما اگر آن کد دارای ویژگی های Babel باشد، مانند کلاس MyComponent { #privateField = 5; }، Babel آن را به کدی تبدیل میکند که نسخههای Node قدیمیتر میتوانند اجرا کنند، و سپس لودر آن کد تبدیلشده را به Node میفرستد.
-
قلاب تبدیل: صبر کنید، برخی افراد بار را با هم مخلوط می کنند و تبدیل می کنند، اما بیایید شفاف سازی کنیم. قلاب بار جایی است که تغییر شکل میگیرد، اما بر اساس API Babel ساخته شده است، که به شما امکان میدهد تنظیمات و افزونههای مورد استفاده را پیکربندی کنید. برای مثال، اگر پروژه شما از @babel/preset-env استفاده میکند، لودر آن پیکربندی را از فایل babel.config.json شما میکشد، آن را روی هر ماژولی که بارگیری میکند اعمال میکند و کدهای سازگار را بیرون میدهد. نیازی نیست ابتدا هر فایلی را از پیش کامپایل کنید – می توانید کد خود را تغییر دهید و تغییرات را فورا مشاهده کنید، که یک تغییر دهنده بازی برای گردش کار توسعه است.
اما نکته اینجاست: ما یک تامین کننده لودر هستیم، نه فقط یک وبلاگ ابزار تصادفی. پس چرا این موضوع برای افرادی که ابزار، برنامهها یا حتی محیطهای JS سازمانی میسازند اهمیت دارد؟ بیایید در مورد موارد استفاده صحبت کنیم. اگر در حال ساختن یک چارچوب سفارشی یا ابزاری برای ساخت هستید که نیاز به پشتیبانی از ESM در نسخههای مختلف Node دارد، babel-esm-loader شما را از نوشتن منطق تبدیل ماژول خود از ابتدا نجات میدهد. بهجای ساخت یک کامپایلر کامل، از اکوسیستم آزمایششده Babel برای مدیریت پشتیبانی نحو استفاده میکنید، در حالی که لودر ادغام با سیستم ESM Node را انجام میدهد.
صبر کنید، اما بیایید به یک مشکل رایج بپردازیم. بسیاری از توسعه دهندگان جدید به این فکر می کنند که فقط "Babel را در ESM اجرا کنید"، اما خیر - قلاب های ESM Node فقط در Node 12 و بالاتر در دسترس هستند و لودر باید قوانین API خاصی را دنبال کند. به عنوان مثال، در Node، قلاب بار باید یک شی را با فرمت (مانند 'ماژول' برای ESM)، کوتاه (محتوای فایل به عنوان یک رشته) و sourceMap (در صورت نیاز) برگرداند. babel-esm-loader اطمینان حاصل می کند که همه این مقادیر بازگشتی صحیح هستند، بنابراین Node در مورد فرمت های ماژول نامعتبر خطا ایجاد نمی کند.
سوال رایج دیگر: تفاوت این با @babel/register چیست؟ @babel/register برای CommonJS است، درست است؟ به (()) قلاب میشود، بنابراین با فراخوانهای نیاز به سبک قدیمی کار میکند، اما ESM را لمس نمیکند. Babel-esm-loader به طور خاص برای ESM است، به این معنی که با دستورهای import، dynamic import()، و تمام ویژگیهای ESM مدرن که @babel/register از آن استفاده نمیکند، کار میکند. به همین دلیل است که ما آن را برای هر پروژه ای که به طور کامل از ESM استفاده می کند و نیاز به ادغام Babel بدون مرحله ساخت کامل دارد، توصیه می کنیم.
اکنون، بیایید به نحوه عملکرد این کار از نقطه نظر عملی برای مشتریان خود بپردازیم. هنگامی که یک برنامه نویس از ابزارهای یکپارچه لودر ما استفاده می کند، ما اغلب آنها را در راه اندازی babel-esm-loader با پیکربندی Babel موجود آنها راهنمایی می کنیم. به عنوان مثال، اگر babel.config.json شما دارای:
{
"پیش تنظیم": ["@babel/preset-env"]،
"plugins": ["@babel/plugin-proposal-class-properties"]
}
تنها کاری که باید انجام دهید این است که node --loader babel-esm-loader your-script.js را اجرا کنید و هر ماژول وارد شده در اسکریپت شما به طور خودکار از Babel عبور می کند. بدون مرحله ساخت اضافی، بدون دستور کامپایل جداگانه - همه اینها در پرواز انجام می شود. این نوعی ادغام است که باعث میشود ابزار بدون درز احساس شود، درست مانند اینکه چگونه لودر مناسب برای تجهیزات سنگین باعث میشود کار سریعتر انجام شود.
صبر کنید، بیایید به پیوند Skid-steer Loader که قبلاً اشاره کردم، دایره ای برگردیم. به لودری مانند آن فکر کنید: این خود کار نیست، این ابزاری است که به شما امکان میدهد مواد (یا در مورد ما، کد) را دقیقاً در جایی که به آن نیاز دارید، بدون کار دستی منتقل کنید. اگر سعی کردید باری از خاک را با بیل جابهجا کنید، مانند تلاش برای اجرای JS مدرن بدون ابزاری مانند babel-esm-loader است - کند، ناکارآمد است، و در نهایت با مشکل مواجه خواهید شد.
اکنون، بیایید در مورد برخی از به روز رسانی های اخیر babel-esm-loader صحبت کنیم. در سال 2023، نگهدارندهها برای وارد کردن فایلهای JSON پشتیبانی اضافه کردند که یک مشکل رایج بود. قبل از آن، اگر بخواهید یک فایل JSON را در یک ماژول ESM با لودر وارد کنید، با خطا مواجه می شود زیرا Node فرمت را تشخیص نمی دهد. اکنون، می توانید وارد کردن pkg از './package.json' assert { type: 'json' }; و لودر تجزیه آن JSON را در کنار تبدیل JS شما انجام خواهد داد. این به روز رسانی کوچک باعث شد که لودر برای برنامه های دنیای واقعی مفیدتر باشد.
نکته دیگری که باید توجه داشته باشید: اگر از TypeScript استفاده می کنید، babel-esm-loader با TypeScript نیز کار می کند. شما فقط باید @babel/preset-typescript را به پیکربندی Babel خود اضافه کنید، و لودر انواع TypeScript را حذف کرده و کد را به JS ساده تبدیل می کند. این بدان معنی است که می توانید کد ESM TypeScript را بنویسید و آن را مستقیماً در Node اجرا کنید، بدون نیاز به مرحله ساخت tsc - برای آزمایش سریع یا پروژه های کوچک عالی است.
اما بیایید صادق باشیم: این یک گلوله نقره ای نیست. مواردی وجود دارد که babel-esm-loader کار نمی کند. برای مثال، اگر کدی مینویسید که منحصراً از ماژولهای CommonJS استفاده میکند و به ESM نیازی ندارید، @babel/register هنوز هم مناسبتر است. همچنین، اگر در حال ساخت یک برنامه تولیدی هستید، ممکن است همچنان بخواهید از مرحله ساخت سنتی (مانند Webpack یا Rollup) برای بهینهسازی، تقسیم کد و کوچکسازی استفاده کنید. لودر برای گردش کار توسعه طراحی شده است، نه استقرار تولید - اگرچه می تواند با ابزارهای تولید جفت شود تا آزمایش محلی را ساده کند.
اکنون، بهعنوان یک تامینکننده لودر، به شما میگویم مشتریان ما چه چیزی را در مورد babel-esm-loader بیشتر دوست دارند: زمان راهاندازی را کاهش میدهد. بسیاری از برنامهنویسهای تازه وارد ESM ساعتها صرف یافتن چگونگی همکاری Babel و Node میکنند، و این لودر آن را حذف میکند. به جای نوشتن قلاب های ماژول سفارشی یا درهم ریختگی با تنظیمات Webpack، فقط یک پرچم را اجرا کنید و بروید. این ارزش یک لودر خوب است: پیچیدگی فرآیند را از بین می برد.
صبر کنید، بیایید کمی عمیق تر به منطق سطح کد شیرجه بزنیم. بیایید به یک نسخه ساده شده از کارهایی که قلاب بار ممکن است انجام دهد نگاه کنیم (نگران نباشید، بدون کد فنی فوق العاده، فقط اصل مطلب):
بارگذاری تابع ناهمگام (url، زمینه، بارگذاری پیش فرض) {
// ابتدا از بار پیش فرض Node برای دریافت محتوای فایل خام استفاده کنید
const { source, format } = await defaultLoad(url, context, defaultLoad);
// Babel را فقط در صورتی اعمال کنید که فایل JS باشد و با ESM سروکار داشته باشیم
if (format === 'module' && /.(js|mjs|cjs)$/.test(url)) {
// پیکربندی Babel را از فایل پیکربندی پروژه بردارید
const babelConfig = require('./babel.config.json');
// کد منبع را با Babel تبدیل کنید
const transformed = require('@babel/core').transformSync(source, {
... babelConfig،
نام فایل: url، // به بابل بگویید در حال پردازش کدام فایل است
})؛
// کد تبدیل شده را به عنوان بازگشت ESM برگردانید { منبع: transformed.code, format: 'module', };
}
// اگر فایل JS ESM نیست، نتیجه بارگذاری پیشفرض را برگردانید
بازگشت defaultLoad (url، متن، defaultLoad)؛
}
این هسته اصلی نحوه کار لودر است. این یک کد کوچک است، اما چسب بین سیستم ESM Node و موتور تبدیل Babel است. برای یک تامین کننده، این نقطه شیرین است: یک ابزار متمرکز که یک مشکل خاص را حل می کند، بدون اینکه با ویژگی های اضافی پف کند.
اکنون، بیایید در مورد مشکلات رایج مشتریانمان در هنگام استفاده از این لودر صحبت کنیم. یکی از موارد مهم، تنظیمات پیشتنظیم شده بابل اشتباه است. اگر اهداف env از پیش تعیین شده شما خیلی باریک هستند، ممکن است کد تبدیل شده همچنان در نسخه های قدیمی Node کار نکند. اگر آنها خیلی گسترده باشند، کار غیر ضروری انجام می دهید و فیلمنامه خود را کند می کنید. ما همیشه به مشتریان کمک میکنیم تا پیکربندی Babel خود را هنگام راهاندازی لودر بررسی کنند، بنابراین برای محیط آنها بهینه شده است.
مشکل دیگر مربوط به وابستگی هایی است که به طور انحصاری از CommonJS استفاده می کنند. اگر یک ماژول CommonJS (مانند 'lodash') را از طریق لودر وارد کنید، Node خطا می دهد زیرا ماژول های CommonJS ESM بومی نیستند. صبر کنید، نه – در واقع، نسخههای اخیر Node از interop بین ESM و CommonJS پشتیبانی میکنند، اما لودر همچنان آن را با ترجمه تماسهای CommonJS به کد سازگار با ESM مدیریت میکند. بیشتر اوقات، بدون هیچ گونه تنظیمات اضافی کار میکند، اما گاهی اوقات با ماژولی مواجه میشوید که به جهانیهای خاص CJS مانند ماژول یا صادرات متکی است، که لودر باید آن را چند بار پر کند. ما برای آن موارد نیز راه حل های سریع داریم.
در پایان روز، babel-esm-loader یک مثال کامل از اهمیت لودر در ابزار جاوا اسکریپت است. این فقط در مورد پردازش کد نیست - بلکه در مورد پر کردن شکاف بین استانداردها و محیط های مختلف است، بنابراین توسعه دهندگان می توانند به جای مبارزه با ابزارهای ساخت، روی نوشتن کد تمرکز کنند. درست مانند اینکه چگونه یک لودر Skid-steer یک سایت ساخت و ساز گل آلود و ناهموار را به فضایی تبدیل می کند که کار می تواند به طور موثر انجام شود، این لودر یک گردش کار از هم گسیخته ESM+Babel را به چیزی صاف و آسان تبدیل می کند.
اگر از مراحل ساخت نامرتب خسته شده اید، یا اگر تیم شما در تلاش است تا ESM و Babel با هم کار کنند، ما می توانیم به شما کمک کنیم babel-esm-loader را در جریان کاری خود ادغام کنید - بدون راه اندازی پیچیده، بدون اصطلاحات، فقط ابزاری که دقیقاً همان کاری را انجام می دهد که شما نیاز دارید. برای بحث در مورد نیازهای پروژه خود و دریافت راه حل سفارشی متناسب با پشته شما، با ما تماس بگیرید.
مراجع:
- Node.js ESM Loader Hooks Documentation
- مستندات رسمی Babel برای ادغام API
- راهنمای صنعت لودر Skid-steer (برای زمینه عملکرد لودر)
- بحث های جامعه در مورد گردش کار ESM + Babel
