ساخت اپلیکیشن های مدرن با Webpack — به زبان ساده

۳۰۱ بازدید
آخرین به‌روزرسانی: ۲۸ شهریور ۱۴۰۲
زمان مطالعه: ۷ دقیقه
ساخت اپلیکیشن های مدرن با Webpack — به زبان ساده

اغلب افرادی که از فریمورک‌های فرانت‌اند مختلف مانند ReactJS, Vue, Angular و غیره استفاده می‌کنند، با Webpack آشنا هستند و به طور متناوب از آن استفاده می‌کنند. اما باید بدانید که Webpack صرفاً برای استفاده به همراه فریمورک‌ها نیست. شما می‌توانید از Webpack بر روی جاوا اسکریپت محض نیز استفاده کنید. ما در این نوشته به توضیح در مورد Webpack و کارهایی که در پیکربندی‌های مختلف می‌توان انجام داد پرداخته‌ایم.

Webpack چیست؟

WEBPACK

Webpack ابزاری است که ماژول‌های مختلف جاوا اسکریپت را انتخاب کرده و آن‌ها را در یک ماژول جاوا اسکریپت منفرد ادغام می‌کند به طوری که بتوان آن را به مرورگر کاربران ارسال کرد.

البته شاید این تعریف، کاری که Webpack انجام می‌دهد را بیش از حد ساده‌سازی کرده باشد؛ اما برای افرادی که با ماهیت آن آشنا نیستند، مناسب خواهد بود. برای توصیف بیشتر باید گفت که Webpack یک «نرم‌افزار بسته‌بندی» (bundler) است که به دنبال ماژول‌های دارای وابستگی، (یعنی فایل‌های جاوا اسکریپت که به کدهایی در فایل‌های دیگر نیاز دارند) می‌گردد، آن‌ها را در هم ادغام می‌کند و سپس یک فایل جاوا اسکریپت می‌سازد که هیچ وابستگی ندارد. بدین ترتیب می‌توان این فایل را به آسانی به مرورگر ارسال کرد.

تاریخچه Webpack

برای درک مسائلی که Webpack تلاش می‌کند آن‌ها را حل کند، باید اندکی با تاریخچه خود Webpack آشنا باشیم. برای این که این بخش کوتاه باشد، تنها دو ابزار مهم و یک مفهوم اساسی را ارائه کرده‌ایم.

  • «کیت ابزار وب گوگل» (Google Web Toolkit): این کیت ابزار، فریمورکی ارائه شده از سوی گوگل است که جاوا را به جاوا اسکریپت تبدیل می‌کند. یکی از ویژگی‌های جالب آن «افراز کد» (code spiliting) است. این مفهوم را در ادامه بیشتر توضیح خواهیم داد.
  • Modules_Webmake: این کتابخانه‌ای است که Webpack از آن ساخته شده است. این کتابخانه اساساً ابزاری است که به ما امکان سازماندهی فایل‌های جاوا اسکریپت برای مرورگر را می‌دهد و این کار را به همان روشی که NodeJs اجرا می‌کند، انجام می‌دهد.
  • IIFE: این مفهوم به معنی بیان تابعی است که بی‌درنگ اجرا می‌شود. در واقع تابع‌های جاوا اسکریپت IIFE تابع‌هایی هستند که همزمان که ایجاد می‌شوند اجرا خواهند شد.

بیان تابع با اجرای بی‌درنگ

ما یک بخش را به این مفهوم اختصاص داده‌ایم زیرا باید در مورد آن بیشتر صحبت کنیم. در تصویر زیر نمونه‌ای از یک IIFE را می‌بینید:

IIFE

اگر قرار بود این تابع را در تگ Script قرار دهیم، این تابع بی‌درنگ اجرا می‌شد. تگ اسکریپت از سوی مرورگر بارگذاری می‌شود. در واقع به نوعی معادل الصاق یک تابع به window.onload است؛ اما یک مزیت اضافی دارد.

به دلیل طرز کار خاص «بستارها» (closures) در جاوا اسکریپت، همه متغیرهایی که در IIFE اعلان شوند دامنه‌شان درون آن تابع خواهد بود. این بدان معنی است که دیگر مشکلاتی مانند تصادم فضای نام در کد نداریم؛ اما در عین حال همچنان به تابع‌هایی که به وسیله IIFE اعلان می‌شوند نیز دسترسی داریم.

چرا باید از Webpack استفاده کنیم؟

اینک باید به این سؤال پاسخ دهیم که Webpack کدام یک از مشکلات امروزی ما را حل می‌کند؟

ابتدا ما با تگ script مشکل داریم. تصور کنید روی کدی کار می‌کنید که هر صفحه HTML دست کم 30 تگ script با ترتیب کاملاً منظم دارد. شاید از نظر برخی افراد این وضعیت، مشکلی محسوب نشود؛ اما در واقع مرورگر مجبور است برای هر فایل یک درخواست ارسال کند و بدین ترتیب عامل «زمان بارگذاری» (time to load) صفحه افزایش می‌یابد. ضمناً تگ‌های اسکریپت معمولاً مدیریت دشواری دارند و تغییر دادن تنها یکی از آن‌ها در ترتیب معین می‌تواند موجب بروز مشکل شود.

همچنین دلیل دوم استفاده از Webpack آن است که ما با مشکل مدیریت فضای نام مواجه هستیم که می‌تواند بسیار به هم ریخته و شلوغ شود. البته برخی توسعه‌دهنده‌ها در زمینه نامگذاری متغیرها کاملاً هوشمندانه عمل می‌کنند؛ اما وقتی در تیم‌های بزرگ کار می‌کنید، ممکن است مواقعی باشند که نام‌های متغیرها با همدیگر تصادم داشته باشند. حتی ممکن است یک توسعه‌دهنده از یک نام متغیر در دو جای کد استفاده کرده باشد.

برخی تیم‌ها، توسعه‌دهنده‌ها را الزام می‌کنند که متغیرها را همواره در دامنه تابع‌ها تعریف کنند؛ اما همیشه نمی‌توان از این وضعیت مطمئن بود. در هر حال این وضعیت موجب می‌شود که رعایت «اصل جداسازی دغدغه‌ها» که یک اصل مهم در برنامه‌نویسی است، دشوار گردد.

دلیل سوم برای استفاده از Webpack این است که اگر به خاطر داشته باشید، گفتیم Webpack از modules_webmake منشأ یافته است. از آنجا که Webpack امکان سازماندهی فایل‌ها را به همان روش NodeJS (استفاده از CommonJS) به ما می‌دهد این مزیت افزوده را داریم که می‌توانیم کد ماژولار بنویسیم که مقیاس‌بندی مناسبی داشته باشد. این وضعیت برای توسعه‌دهنده‌های فرانت‌اند بسیار حائز اهمیت است.

CommonJS

CommonJS

ما قصد نداریم توضیح زیادی در خصوص CommonJS بدهیم، زیرا در حیطه موضوعی این مقاله نمی‌گنجد. اما می‌توانید تصور کنید که CommonJS یک سیستم ماژول جاوا اسکریپت است که از سوی NodeJs استفاده می‌شود.

Webpack امکان استفاده از این ماژول و حتی بهتر از آن سیستم ماژول ES را در مرورگر بدون هیچ مشکلی فراهم می‌کند. این وضعیت موجب می‌شود که بتوانیم کد کاملاً ماژولار و قابل نگهداری بنویسیم که در آن فایل جاوا اسکریپت می‌تواند یک کارکرد منفرد را مدیریت کند. بدین ترتیب اصل «مسئولیت منفرد» که یکی دیگر از اصول مهم برنامه‌نویسی است رعایت می‌شود.

ماژول‌های ES یا EMS

ES Modules

این نیز یک سیستم ماژول دیگر است که هم اینک از سوی مرورگرها پیاده‌سازی شده است. اما متأسفانه این سیستم نیز محدودیت‌های خاص خود را دارد. Webpack امکان استفاده از این سیستم بدون هیچ مشکل را نیز در اختیار ما قرار می‌دهد. باید توجه داشته باشید که استفاده از ESM موجب می‌شود که اغلب کدها خوانایی بهتری پیدا کنند.

طرز کار Webpack چگونه است؟

طرز کار Webpack به طور ساده به شرح زیر است:

  • Webpack یک مسیر به سمت یک «نقطه ورودی» (entry point) منفرد می‌گیرد که یک فایل جاوا اسکریپت است و به دنبال گزاره‌های مهم می‌گردد. این موارد می‌توانند ESM یا CJS باشند.
  • سپس Webpack فایل ایمپورت شده را پیمایش می‌کند و به دنبال گزاره‌های مهم می‌گردد و همزمان در این فرایند یک گراف وابستگی ایجاد می‌کند.

برای توضیح بیشتر به تصویر زیر نگاه کنید:

Webpack

در این جا دو فایل به نام‌های index.js و helpers.js داریم. این دو فایل تابع‌های متفاوتی را اجرا می‌کنند؛ اما ما تابع موجود در فایل helpers.js را در فایل index.js ایمپورت کرده و مورد استفاده قرار می‌دهیم. نقطه ورودی Webpack به صورت پیشفرض، مسیر src/index.js/. است و از آنجا تلاش می‌کند که گراف وابستگی را به صورت زیر بسازد:

Webpack

آغاز کار با Webpack

برای این که درک بهتری از طرز کار Webpack داشته باشید، قصد داریم که اپلیکیشن TODO ساده بسازیم. این اپلیکیشن صرفاً دو کارکرد ساده افزودن و حذف ToDo ها را دارد و قصد داریم آن را با استفاده از پیکربندی پیش‌فرض Webpack بسته‌بندی کنیم و از این رو هیچ فایل پیکربندی Webpack نخواهیم داشت. اپلیکیشن ما به صورت زیر است:

Webpack

گام نخست، ایجاد یک دایرکتوری پروژه جدید و ایجاد دو پوشه است که نام یکی از پوشه‌ها dist و نام دیگری src است. به طور پیشفرض نقطه ورودی Webpack مسیر src/index.js/. است و یک فایل جاوا اسکریپت بسته‌بندی شده را در مسیر dist/main.js/. خروجی می‌دهد که بدین ترتیب دو پوشه ایجاد کرده‌ایم.

در پوشه dist می‌توان یک فایل به نام index.html ساخت. این فایل لزوماً اختصاص به Webpack ندارد و می‌توان آن را در هر کجای دایرکتوری پروژه قرار داد و می‌توان در فایل main.js به آن ارجاع داد. در نهایت، ساختار پروژه باید چیزی مانند زیر باشد:

Webpack

ما در پوشه src یک فایل به نام index.html ساخته‌ایم که پیاده‌سازی کارکردهای اپلیکیشن TO-DO را آغاز می‌کند. اما قبل از آن باید فایل index.html را مقداردهی بکنیم. از آنجا که ایجاد اپلیکیشن TO-DO بخشی از این راهنما محسوب نمی‌شود، صرفاً کد زیر را ارائه می‌کنیم:

1<html>
2  <head>
3    <title>Todo App</title>
4  </head>
5  <body>
6    <div class="container">
7      <p>
8        <label for="new-task">Add Item</label>
9        <input id="new-task" type="text">
10        <button id="addTask">Add</button>
11      </p>
12      
13      <h3>Todo</h3>
14      <ul id="tasks">
15      </ul>
16    </div>
17    <script src="main.js"></script>
18  </body>
19</html>

راه‌اندازی اپلیکیشن

در ادامه این اپلیکیشن را فعال می‌کنیم. ما قصد داریم آن را به دو تابع (حذف و اضافه) تقسیم کنیم که هر یک در فایل مستقلی قرار می‌گیرد و سپس آن‌ها را در فایل index.js ایمپورت می‌کنیم. بنابراین دو فایل در پوشه src به نام‌های addTask.js و deleteTask.js می‌سازیم. ساختار پروژه اینک باید مانند تصویر زیر باشد:

Webpack

اینک می‌توانیم شروع به اضافه کردن منطق مورد نیاز خود بکنیم و از این رو ابتدا deleteTask.js را پیاده‌سازی می‌کنیم، زیرا هیچ وابستگی ندارد. کد زیر را در فایل deleteTask.js قرار دهید:

1const deleteTask = function(e) {
2  console.log("Delete Task...", e);
3  //Remove the parent list item from the ul
4  var listItem = e.target.parentNode;
5  var ul = listItem.parentNode;
6
7ul.removeChild(listItem);
8};
9
10export default deleteTask;

همه کاری که در این کد انجام می‌دهیم این است که یک تابع deleteTask ایجاد کرده و سپس آن را به صورت اکسپورت پیش‌فرض، اکسپورت می‌کنیم.

در ادامه می‌توانیم تابع addTask را پیاده‌سازی کنیم. کد زیر را به فایل addTask.js اضافه کنید:

1import deleteTask from "./deleteTask";
2
3const createNewTaskElement = function(taskString) {
4  const listItem = document.createElement("li");
5  const label = document.createElement("label");
6  const deleteButton = document.createElement("button");
7
8deleteButton.innerText = "Delete";
9  deleteButton.className = "delete";
10  deleteButton.addEventListener("click", deleteTask);
11
12label.innerText = taskString;
13
14listItem.appendChild(label);
15  listItem.appendChild(deleteButton);
16
17return listItem;
18};
19
20const addTask = function(e) {
21  const taskList = document.getElementById("tasks");
22  const task = document.getElementById("new-task");
23  if (task.value !== "") {
24    const newTaskItem = createNewTaskElement(task.value);
25    taskList.appendChild(newTaskItem);
26    task.value = "";
27  }
28};
29
30export default addTask;

طراحی فایل‌های مختلف

در این کد ابتدا فایل deleteTask.js را ایمپورت کرده‌ایم. به صورت پیش‌فرض اگر هیچ پسوندی در ایمپورت ذکر نشود، Webpack به صورت خودکار تصور می‌کند که یک فایل js. است. سپس تابعی را داریم که آیتم لیستِ شامل وظیفه‌ای که در فرم وارد شده است را ایجاد می‌کند. تنها نکته‌ای که در این مرحله باید توجه کنیم این است که تابع حذف را به handler کلیک برای دکمه delete الصاق کنیم. سپس تابع اصلی addTask را ایجاد و آن را اکسپورت می‌کنیم.

در گام بعدی باید تابع addTask را در فایل index.js ایمپورت کنیم. کد زیر را در فایل index.js خود قرار دهید:

1import addTask from './addTask';
2
3const addTaskButton = document.getElementById("addTask");
4addTaskButton.addEventListener("click", addTask);

این کد کاملاً سرراست است. ما تابع addTask را ایمپورت کرده و آن را به handler کلیک برای addTaskButton الصاق کرده‌ایم. اگر مراحل فوق را پیگیری کرده باشید اینک آماده اجرای برنامه هستیم.

در نهایت فایل main.js را داریم که برای اجرای Webpack روی کد مورد نیاز است. در این مرحله باید مطمئن شویم که NodeJS روی سیستم نصب است و سپس Webpack را به صورت سراسری با استفاده از دستور زیر نصب کنیم:

npm install -g webpack OR sudo npm install -g webpack

زمانی که کار نصب پایان گرفت، دستور زیر را اجرا کنید:

Webpack

این دستور فایل ما را با موفقیت بسته‌بندی می‌کند، اما احتمالاً با هشدار زیر در پنجره ترمینال مواجه می‌شویم:

Webpack

Webpack صرفاً به ما هشدار می‌دهد که ما به هیچ mode-ی اشاره نکرده‌ایم. ما می‌توانیم اهمیتی به این هشدار ندهیم و کد را اجرا کنیم، چون همه چیز به درستی کار خواهد کرد. اما اگر از این هشدار خوشتان نمی‌آید، می‌توانید Webpack را به صورت زیر اجرا کنید:

webpack --mode=development

بدین ترتیب کار Webpack به پایان رسیده است.

جمع‌بندی

اگر در هر بخش از این راهنما دچار مشکل شدید، می‌توانید از ریپازیتوری این راهنما روی گیت‌هاب (+) استفاده کنید. امیدواریم این مقاله روش استفاده از Webpack را به شما آموخته باشد؛ هر چند در این راهنما از هیچ پیکربندی برای آن استفاده نکردیم. شما باید با برخی پیکربندی‌های خاص مانند code splitting ،lazy loading و پیکربندی Webpack برای کار با اپلیکیشن‌های چندصفحه‌ای نیز آشنا باشید.

دقت کنید که ما برای ساده نگه داشتن این راهنما از فایل package.json استفاده نکردیم. استفاده از فایل package.json و نصب محلی Webpack روشی مناسبی برای مقیاس‌بندی محسوب می‌شود.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۰ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
freecodecamp
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *