درک برنامه نویسی ماژولار در جاوا اسکریپت

درک برنامه نویسی ماژولار در جاوا اسکریپت

شاید خیلی از شما در طول مدت برنامه نویسیتون راجب ماژول و برنامه نویسی ماژولار شنیده باشید و منطق اون رو درک کرده و از اون استفاده هم کرده باشید . خب اگه چنین شخصی هستید که دارید این مقاله رو میخونید چه بهتر اما اگر نیستید هم نگران نباشید. اینجا میخوایم راجب برنامه نویسی ماژولا توی جاوا اسکریپت صحبت کنیم واگر شما قبلا این روش روی توی زبان های دیگه استفاده کرده بودید باید بدونید که از اونجایی که کلا جاوا اسکریپت خیلی چیزاش با بقیه زبان ها فرق داره توی این مورد هم متفاوته و واسه همین برنامه نویسی ماژولار کلی داستان خواهیم داشت! در هر صورت بزارید بریم سر بحث اصلی.

چرا برنامه نویسی ماژولار

فکر می کنم جواب این سوال خیلی سخت نباشه ، هر برنامه نویسی دوست داره که کد هایی رو که ممکنه چندین بار ازشون استفاده کنه رو دوباره ننویسه و فقط توی جاهای مختلف اون هارو فراخوانی کنه .با دسته بندی کردن برنامه و استفاده دوباره از کد هامون هم برنامه ساختار خوبی میگیره هم برنامه نویسی راحت تره . با این کار نگهداری کد ها هم راحت تر میشه واگه بعدا قرار شد کدی تغییر کنه لازم نیست شما توی همه ی برنامه برید و کد رو تغییر بدید. از طرفی وقتی شما توی جاوا اسکریپت ماژولار می نویسید هر ماژول شما Scope  خاص خودش رو میگیره و این خیلی خوبه که شما فضای کلی برنامتون رو با متغیر ها توی هر ماژول پر نمی کنید(یا اصطلاحا کثیف نمی کنید) که بعدا به مشکل بخورید.
خب بریم سر اصل مطلب
حالا وقتشه که ببنیم چطور میتونیم توی جاوا اسکریپت ماژولار بنویسیم. برای این کار راه های مختلفی وجود داره ، اولین سوالی که ممکنه ذهن شما رو درگیر کنه اینه که خب ما بحث ماژول رو توی ES6 داریم و قضیه تمومه. اما نه ، درسته که بحث ماژول توی ای اس معرفی شده اما هنوز هیچ مرورگری برنامه نویسی ماژولار رو با جی اس پشتیبانی نمیکنه. حالا تکلیف ما چیه ؟ مجبوریم از کتابخونه ها برای این کار استفاده کنیم یا دقیق تر از Module Bundler  ها استفاده کنیم، که این کار رو برای ما انجام میدن.

پس ما میخوایم دقیقا کاری رو که توی نود جی اس انجام میدیم رو سمت کلایت انجام بدیم ینی به همون حالت بتونیم فایل هامون رو سمت کلایت require  کنیم . آها تا یادم نرفته ما بدون استفاده از کتابخانه هم میتونیم ماژولار بنویسیم و روش هایی برای این کار هست که خب من توصیه نمی کنم و در واقع یجور چرخوندن لقمه هستش وقتی کتابخونه هایی با قابلیت های بسیار این کار رو انجام میدن ما بیام خودمون این کارو بکنیم که توش ممکنه به دردسر هم بخوریم.

خب بریم ببین این کتابخونه ها چطور تقسیم می شن . و ما کدوم رو بهتره انتخاب کنیم. برای نوشتن برنامه های ماژولار سمت کلاینت شما در واقع سه تا انتخاب دارید CommonJS  وAMD   و ES6 که هر کدوم رو توضیح میدیم.( که همه ی اون کتابخونه ها بر اساس یکی از این سه نوشته شدن)

دو تای اولی یعنی CommonJs  و AMD معمولا با نام Scriptloader  شناخته می شند. توجه کنید که اینها کتابخونه و… نیستند بلکه چیزی  شبیه یک استاندارد یا یک روش هستند برای استاندارد سازی کد هایی  که بقیه مینویسن.

CommonJS

ماژول کامن جی اس قطعه کد جاوا اسکریپتی هستش که در قالب آبکجت از هر ماژول خارج میشه و میتونیم ازش استفاده کنیم . خود نود جی اس هم از کامن جی اس استفاده می کنه پس اگر با نود کار کرده باشید راحت تر می تونید Common  رو یاد بگیرید.  بزارید کدی از Common  رو با هم ببینیم :

 

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

خب اینطور کد نوشتن توی جاوا اسکریپت همونطور که گفتم میتونه Scope  کل برنامه ی مارو تمیز نگه داره و خب فایده دیگش هم مشخصه که از کدهامون میتونیم همه جا استفاده کنیم و تکرارشون نکنیم. در ضمن دیدید کدش چقد هم ساده هست.

نکته ی مهم راجب CommonJs  اینه که ماژول ها رو بصورت همزمان  (synchronously  ) لود می کنه . یعنی اگر شما سه تا فایل داشته باشید به ترتیبی که نوشته شدند لود میشن (یکی پس از دیگری)

AMD

خب حالا اگر بخواید فایل ها رو بصورت غیر هم زمان لود کنید چی؟

اونموقع انتخاب شما AMD  خواهد بود. بزارید اینجا هم به نمونه کدی نگا بندازیم :

خب اما باید این رو هم بگیم که خیلی ها این روش (غیرهم زمان) رو برای برای لود کردن فایل های جاوا اسکریپت نمی پسندن ؛ و همچنین سینتکس CommonJs و es6 رو راحت تر میدونن.

خب آیا همین جا تموم میشه و دیگه انتخاب دیگه ای نداریم؟

UMD

برای وقتی که شما هر دو رو نیاز داشتید.

ES6

خب آخرین انتخاب هم es6  هست. البته درستش اینه که بگیم خوده جاوا اسکریپت . که احتمالا هم راجبش شنیدید. برای اطلاعات بیشتر راجب ماژول ها در es6 میتونید این لینک رو ببینید.

نمونه ی کد سینتکس es6 :

خب قبل از اینکه کتابخونه های مربوط هر 4 روش رو که بالا معرفی کردم بگم یه سری مطالب هست که باید بدونیم.

کتابخونه هایی که ما میخوایم در چند خط بعدی ازشون آگاه شیم همونطور که گفتم با اسم Module bundler (یا دسته کننده ماژول) شناخته می شند. خب ابتدا بیایم ببینیم که اصلا ماژول bundle کردن یعنی چی و ما اصلا برای چی باید ماژول های خودمون رو ترکیت کنیم.

باندل کردن ماژول ها در واقع به عمل کنار هم گذاشتن ماژول ها تحت ترتیب درست اون ها و نهایتا بیرون دادن خروجی توی یک فایل هستش.

خب ممکن بگید ترتیب درست یعنی چی؟ فرض کنید ماژولی داریم که وابستگی به Jquery داره ، اگر ما بخوایم ماژول ها رو کنار هم تنها توی یک فایل قرار بدیم باید مطمعن بشیم که ابتدا خود Jquery لود بشه و بعد از اون این ماژولی که ما نوشتیم و وابسته به Jquery   هستش . واگر نه کد هامون کار نمیکنه.

اصلا چرا باید ماژول های خودمون رو ترکیب و یک فایل خروجی بگیریم؟

برای چی باید یک فایل خروجی باشه چرا از همون ماژول ها هر کدوم رو که نیاز داشتیم رو توی مرورگر لود نکنیم. دلیلش واضحه به خاطر اینکه هر بار که شما یک تگ <script> به صفحه خودتون اضافه می کنید در واقع دارید سرعت لود خودتون رو پایین میارید. حالا تصور کنید که 15 تا فایل جاوااسکریپت و ماژول داشته باشید ، که باید برای یک صفحه لود بشن. و همچنین اینکه کنار ترکیب کردن شما فایل هاتون رو minify هم می کنید و درواقع یک فایل فشرده توی خروجی خواهید داشت.

بریم سر معرفی کتابخونه های مربوط به روش هایی که توی بالا معرفی کردیم.

برای CommonJs

برای باندل یا ترکیب یا هرچی که شما میخواین اسمشو بزارید با استفاده از CommonJs  شناخته شده ترین روش Browserify هستش. شاید شما هم قبلا اسمشو شنیده باشید.

برای کار با Browserify فرض کنید فایلی به اسم main.js دارید که ماژولی رو وارد میکنه و ازش استفاده می کنه :

خب اینجا ما فقط یک وابستگی برای کدمون داریم و اون هم در واقع myDependency هستش . اگر بخوایم این فایل و وابستگیش رو داخل یک فایل bundle  کنیم دستور:

رو اجرا می کینم و در واقع این دستور فایل main.js  و تمام وابستگی هاش رو با ترتیب درست داخل یک فایل به اسم bundle.js قرار میده.

خبر بد راجب Browserfy اینکه مدت طولانی ای هست که بروز رسانی نشده و درواقع مرده. ولی خیلی ها هنوز ازش استفاده می کنن . همیچنن این ترکیب کننده مثل بقیه ی باندلر ها ی دیگه پلاگین هایی داره که میتونید استفاده کنید.

برای AMD

برای کار با AMD هم شناخته شده ترین RequireJs هست. تا یادم نرفته نکته ای رو راجب AMD  بگم ، همونطور در ابتدا اشاره کردم AMD ماژول ها رو بصورت غیر همزمان لود میکنه . یعنی چه سه تا فایل داشته باشیم چه یدونه خیلی فرقی برای ما نمیکنه چون همشون با هم شروع به دانلود شدن از سرور میشن خب توی چنین شریطی دیگه معنا نداره که فایل ها رو به اصطلاح باندل کنیم. به همین خاطر هم دیگه بیشتر به کتابخونه های AMD باندلر گفته نمیشه و با نام Module loader شناخته می شند.

البته در واقع اینکه ما سه تا فایل داشته باشیم یا یدونه توی سرعت لود ما تاثیر داره ، برای همین هم توی RequireJS هم روش هایی برای باندل کردن ماژول ها وجود داره.

تا یادم نرفته بگم که برای ADM کتابخونه ی دیگه ای به اسم almond هم وجود داره که البته سبک تر هستش.

 

برای  ES6

خب و اما برای روش خود جاوا اسکریپت چی داریم. یکی از مهترین باندلر ها توی این قسمت قرار میگیره یعنی rollup. که راجبش باید بگیم که ادعا میکنه فایلی که در نهایت تحویل شما میده از لحاظ سایز کوچکتر از بقیه ی ماژول باندلر ها هست. همیچنین قابلیتی به اسم tree-shaking که پایین تر راجبش صحبت میکنیم رو معرفی کرده. رول آپ بر اساس یک فایل کانفیگ کار میکنه که  یک نمونه از اون رو اینجا می تونید ببینید اگر یکم به کد هاش دقت کنید یه چیز های دست گیرتون میشه:

Webpack

می رسیم به سر سخت ترین اونها ، از وب پک می تونید برای ترکیب کردن فایل های CommonJs  و AMD و Es  استفاده کنید. Webpack هم مثل rollup ویژگی های خودشو داره برای مثال ویژگی خوبی مثل code-splitting رو معرفی کرده که راجب این هم پایین تر حرف میزنیم. اساس کار وب پک یک فایل کانفیگ هستش که همه ی کار داخل اون انجام میشه برای نمونه یک فایل کانفیک وب پک رو می بینید:

 

خب بریم سر بعضی از ویژگی هایی که راجبشون حرف زدیم ولی توضیح ندادیم.

Tree-shaking

ببینم این ویژگی چیه و چه فایده ای داره. فرض کنید شما ماژولی دارید به اسم util.js که محتوای اون به این صورت هستش:

و حالا فرض کنید که میخواید جایی از برنامتون از این ماژول استفاده کنید. پس برای استفاده از اون ابتدا اون رو فرخوانی می کنید و بعد استفاده می کنید:

اما در واقع اگر ما به کد بالا نگا کنیم می بینیم که ما تنها از یک بخش از فایل خودمون  استفاده کردیم و اون فقط تابع each بوده خب آیا لازمه که ما همه  ی محتوا ی فایل util.js رو دریافت کنیم در حالی که فقط از یه بخش کوچیکش استفاده کردیم؟ ویژگی tree-shaking این قابلیت رو به ما میده که فقط کدی رو که از اون استفاده کردیم رو (بصورت اتوماتیک) اضافه میکنه در واقع نسخه ی shake شده ی کدی که بالا نوشتیم به این صورت میشه :

نه اینکه ما کل محتوای فایل util.js رو بگیریم.

Code-splitting

خب توی قسمت قبل دیدید که کار تشخیص  اتوماتیک بود. درواقع اینجا ما کار رو بصورت دستی انجام میدیم. برای مثال همون مثال بالا رو در نظر بگیرید که ما فقط میخوایم فقط از یه قسمت util استفاده کنیم خب فرض کنید کد مورد نظرمون رو هم نوشتیم یعنی این قسمت:

اینجوری دیگه هر وقت فقط توی یک صفحه به این کد نیاز داشتیم فقط همین کد رو فرخوانی می کنیم. یعنی each.bundle.js رو نه کل bundle.js رو.حالا فرض کنید ما صفحه ای داریم که فقط به این فایل نیاز داره ، پس دیگه احتیاجی نیست که توی اون صفحه بخوایم کل util رو فراخوانی کنیم . خب پس ما این فایل رو به عنوان یک bundle در نظر میگیریم بعد این فایل رو کامپایل می کنیم واگر مثلا اسم فایل each بود خروجی رو میزاریم   each.bundle.js و فایل کامپایل شده که در واقع همین فایل هستش محتواش با وابستگی هاش به این صورت میشه :

یک نکته : اونطور که من فهمیدم وب پک قراره بعدا tree-shaking رو ساپورت کنه اما اگر الان میخواید ازش استفاده کنید باید یک سری کانفیگ رو بصورت دستی خودتون انجام بدید برای اطلاعات بیشتر می تونید به این لینک مراجعه کنید.

خب اما می رسیم به دست کم گرفته شده ترین Module loader

Systemjs

با سیستم جی اس هم میتونید سینتکس های Commonjs  و AMD و Es6 رو بنویسید. سیستم جی ای بر اساس این مخزن ساخته شده که در واقع یک polyfill برای ماژول های es6 هستش که بالا گفتیم فعلا توی هیچ مرورگری ساپورت نمیشن.نمونه کد سیستم جی اس :

Jspm

خب ببینم jspm  چیه. در واقع jspm یک پکیج منجیر برای systemjs هستش و درواقع از npm و github میتونه پکیج های مورد نظر شمارو در یافت کنه . jspm فقط یک پکیج منجیر نیست و در واقع کار های دیگه ای هم میتونه برای شما انجام بده. یعنی در واقع شما پکیج هایی رو که برای npm هست رو برای سمت کلاینت دانلود می کنید و یه سری امکانات اضافی هم به شما میده مثل همون bundle کردن فایل ها.

نکته مهم راجب   jspm اینه که با توجه به http2 ساخته شده.

برای خوندن یک مقاله خوب که webpack رو با jspm مقایسه کرده می تونید به این لینک مراجعه کنید.

خب آیا این همه ی راه های کد زدن ماژولار در جاوااسکریپت هست؟

البته که نه ، اولا اینکه قطعا بجز اینهایی که ما معرفی کردیم کتابخونه های دیگه ای هم هست اما قطعا تعدادشون زیاد نیست و خیلی شناخته شده نیستند.
دوما برای ماژولار نوشتن یک راه دیگه هم هست و اون هم استفاده از transpiler ها در جاوا اسکریپت هستش . برای اطلاعات بیشتر راجب ترنسپایلر ها اینجا مراجعه کنید.

ما اینجا کار با Typescript و Coffescript رو می گیم.

برای کار با Typescript یک نمونه ی کد:

کد های مروبوط به ماژول Typescript  خیلی شبیه به خود  es6 هستند و این خیلی خوبه.

ترنسپایلر بعدی Coffescript هستش که نمونه کد مربوط به قسمت ماژول اون رو هم اینجا می بینید:

 

البته توجه کنید که وقتی از transpiler  ها دارید استفاده می کنید دیگه کارهایی مثل باندل کردن رو نمیتونید انجام بدید. و مهتر اینکه این باندلر هایی که معرفی کردم ابزارهایی دارند که شما میتونید باهاشون داخل (مثلا Webpack ) از Typescript استفاده کنید.

خب امید وارم این مقاله به دردتون خورده باشه در آخر هم یه سری لینک های مفید میزارم که میتونید برای آشنایی بیشتر به اون ها مراجعه کنید :

Lasso  : یک ماژول باندلر جالب دیگه!

Spittable  : این هم یکی دیگه که سینتکس es6 و commonjs رو هم پشتیبانی میکنه و همچنین code-splitting  هم داره.

Steal.js : یک ماژول لودر که هم ES6 هم commonjs  و AMD رو ساپورت میکنه.

لینک مقایسه اندازه فایل خروجی ماژول باندلر ها با هم

یک لینک مقایسه ی اندازه فایل خروجی ایه دیگه

مقایسه ی کد های ماژول بانلدر ها ی  مختلف با هم

آموزش فارسی webpack

  • zareh avanesian

    مرسی از پست خوبتون، لذت بردم

  • Kami Re

    بسیار عالی. نکات مبهمی که وجود داشت برام روشن شد.

  • puria Kordrostami

    خیلی عالی بود.