Webpack - Module Bundler

تحدثنا في مقال سابق عن Webpack من الناحية النظرية، وشرحنا دوره وأهميته في حياة مطوري الويب هذه الأيام.

وكنت قد وعدتكم بأن أقوم بإعداد درس جديد من أجل شرح Webpack واكتشافه بطريقة عملية حتى تترسخ في أذهاننا المفاهيم التي رأيناها في الدرس السابق، وها أنا اليوم أفي بوعدي لكم 🙂

سنسير في هذا الدرس خطوغ بخطوة لنرى كيفية إعداد ويب باك من الصفر من أجل تكييفه مع احتياجات مشروعنا، وقد يكون هذا الدرس طويلا لأنني لا أريد أن أحرق أي مرحلة مهما كانت بسيطة حتى يكون الشرح في متناول المبتدئين والمتقدمين على السواء.

البداية

لننشئ مجلدا اسمه wepback-project ونقوم بالدخول إليه :

ثم لنقم بتهيئة ملف packages.json عن طريق هذا الأمر :

بعد إنشاء الملف packages.json سنقوم بتحميل Webpack 4، وهي آخر نسحة من Webpack لحدود كتابة هذه الأسطر، مع تحميل حزمة Webpack-cli لتنفيذ بعض أوامر Webpack انطلاقا من Terminal.

الآن، عند تنفيذ الأمر webpack  من نافذة Terminal فإنه ستظهر لنا رسالة الخطأ هذه :

الرسالة باللون الأصفر هي فقط رسالة تحذيرية تعلمنا بأن WEBPACK يفترض مسبقا بأننا في وضع الإنتاج (Production) إذا لم نقل له العكس، وبالتالي فإنه قد يقوم بتنفيذ بعض المهام الخاصة بهذا الوضع مثل ضغط ملفات CSS و JS إلخ…

أما الرسالة الثانية باللون الأحمر فهي رسالة خطأ تقول لنا بأن WEBPACK يبحث عن مجلد اسمه src في مشروعنا ولكن لم يجده. فانطلاقا من النسخة الرابعة، أصبح Webpack يعتمد مقاربة zero configuration التي تمكننا من القيام بعدد من المهام الأساسية من دون إنشاء ملف الإعدادات webpack.config.js. لهذا يفترض هذا المحزم بأن هناك مجلد اسمه src وبداخله ملف index.js، ويمكننا طبعا تغيير هذه الإعدادات الإفتراضية عبر ملف webpack.config.js كما سنرى لاحقا، أو حتى من دونه إنطلاقا من الأوامر السطرية فقط :

وضع التطوير

لنقم بإنشاء المجلد src وملف index.js بداخله.

وبما أننا في مرحلة التطوير، فسنطلب من Webpack أن يقوم بعمله بناء على هذا الوضع، والطريقة هي عبر إضافة العلم mode– لأوامر ويب باك :

بعد تنفيذ هذا الأمر، ستتم عملية التحزيم بنجاح لأن ويب باك وجد كل الظروف التي افترضها مسبقا. وستلاحظون بأنه قام بإنشاء مجلد جديد اسمه dist بداخله ملف جافاسكريبت main.js وبداخله كود الجافاسكريبت المحزم، غير مضغوط لأننا طلبنا من Webpack أن يعمل وفق إعدادات وضع التطوير Development.

ولجعل بيئة عملنا أكثر احترافية وعملية، سنقوم بتنفيذ أوامر Webpack من داخل سكريبتات npm التي نقوم بإضافتها داخل الملف package.json في منطقة scripts. إليكم الطريقة :

لإعادة تنفيذ الأمر السابق webpack --mode development ، يكفي تنفيذ هذا الأمر :

بهذه الطريقة يمكننا تنفيذ أوامر npm مهما كانت معقدة، ومهما أظفنا أعلاما وخصائص جديدة لأوامر Webpack فإن أمر npm الذي نقوم بتنفيذه في نافذة Terminal يبقى كما هو. وحتى إذا قدر لمطور آخر أن يعمل على مشروعنا، فسيمكنه معرفة الأوامر التي يجب تنفيذها على المشروع فقط بفتح الملف package.json ومعاينة الأوامر داخل الخاصية {} scripts .

لإضافة وضع بناء جديد خاص بمرحلة الإنتاج، فيمكننا إنشاء سكريبت جديد اسمه مثلا build بنفس الكيفية التي أضفنا بها السكريبت dev.

لكي لا نضطر لإعادة تنفيذ هذه الأوامر بعد كل عملية تعديل على الملف index.js، سنقوم بإضافة علم جديد (flag) اسمه watch– لأوامر Webpack بهذه الكيفية :

لنبدأ العمل في الأمور الجادة

أحدث طريقة لكتابة أكواد الجافاسكريبت معروفة باسم ES6، ولكن مع الأسف لا تدعمها حتى الآن بشكل كامل كل المتصفحات الكبيرة، لذلك علينا تحويل أكواد جافاسكريبت ES6 إلى أكواد جافاسكريبت ES5 مدعومة من كافة المتصفحات. هذه العملية معروفة باسم Transpiling، ويعتبر Babel هو أشهر Transpiler لأكواد الجافاسكريبت في الوقت الحالي.

لنكتشف معا كيفية استخدام Babel مع Webpack 🙂

تحميل وإعداد بابل Babel

أولا علينا تحميل بابل من مستودع npm مع ملحقاته التي سوف نحتاجها.

قمنا هنا بتحميل 3 حزم :

  1. babel-core : الحزمة التي تحتوي على الشفرة المصدرية لنواة بابل.
  2. babel-preset-env : الحزمة التي تمكن نواة بابل من تحويل أكواد جافاسكريبت ES6 إلى أكواد جافاسكريبت ES5.
  3. babel-loader : هذه الحزمة تمثل ال loader الذي يستخدمه webpack لكي يعمل بتوافقية كاملة مع Babel. يعني أن Webpack يستعين ببابل في عملية Transpiling قبل أن يقوم بعملية التجميع أو التحزيم ( Bundling ).
كما شرحنا في المقال السابق، فإن Webpack يعتمد على ما يعرف ب Loaders لكي يتمكن من تحزيم ومعالجة مختلف أنواع الملفات، وليس فقط ملفات جافاسكريبت (صور، CSS، خطوط، JSX ،TypeScript إلخ …).

الآن بعد أن قمنا بتحميل الحزم الثلاث، سنقوم بإنشاء ملف اسمه babelrc. لكي نطلب من بابل أن يستخدم الإضافة babel-preset-env ( تعرف هذه الإضافات في بيئة “بابل” ب Presets ) أثناء عملية Transpiling. ونكتب بداخله ما يلي :

جاء الوقت الآن لنطلب من “ويب باك” أن يستعين ب Babel، سنفعل ذلك عن طريق ملف webpack.config.js الذي ذكرناه أكثر من مرة.

إعداد “ويب باك”

نحن الآن مطالبين بالإستعانة بالملف webpack.config.js من أجل إضافة عدد من الإعدادات المتقدمة ل Webpack.

لنشئ هذا الملف الآن، ولنضع فيه المحتوى التالي :

هذا هو أبسط صورة يمكن أن يكون عليها الملف webpack.config.js، وهذا الكود بسيط حيث يطلب من ويب باك فقط أن يبدأ التحزيم من ملف index.js (يسمى Entry point) على أن يجمع الكود النهائي في ملف main.js (يسمى Output file) وهي كما رأينا سابقا الإعدادات الإفتراضية التي يمكن تغييرها كما شئنا.

لنطلب الآن من Webpack أن يستخدم الحزمة babel-loader لكي نتمكن من كتابة أكواد جافاسكريبت ES6 :

لاحظوا بأننا أضفنا المنطقة {} module، هناك سيتم إضافة وإعداد جميع ال Loaders التي نحتاجها مع webpack في مشروعنا. بداخل المصفوفة rules نضع هذه ال loaders على شكل كائنات من نوع JSON، وكل كائن يضم مجموعة من الخصائص أهمها :

  • test : هذه الخاصية عبارة عن RegEx وتحدد ل webpack أي نوع من الملفات سيقوم بإجراء هذا loader عليها.
  • exclude : الملفات التي نريد استبعادها رغم أنها تحقق ال RegEx المحدد في الخاصية test.
  • use : هذه الخاصية تخبر Webpack بال loaders التي عليه إجراؤها وتطبيقها على هذه الملفات. (babel-loader في حالتنا).

سنفتح الآن الملف index.js ونكتب فيه بعضا من كود جافاسكريبت ES6 :

بعد تنفيذ الأمر npm run dev سنلاحظ بأن Webpack قام بعملية التجميع في الملف main.js مع تحويل الدالة السهمية (Arrow function) أعلاه إلى دالة تقليدية بطريقة جافاسكريبت ES5.

إذن أصبح بإمكاننا الآن كتابة أكواد جافاسكريبت الحديثة في مشروعنا، و Webpack بفضل ال babel-loader سيتولى مهمة تجميعها وتحويلها لأكواد جافاسكريبت ES5 المدعومة من معظم المتصفحات.

ماذا عن ملفات HTML ؟

نحن الآن لدينا ملف dist/main.js المحزم والجاهز للإستدعاء في صفحة الويب، ولكن أين هي هذه الصفحة ؟ لا تقلق، صديقي، سنقوم بإضافتها حالا.

لنقم بإنشاء ملف اسمه index.html داخل المجلد src ونضع فيه المحتوى التالي :

هناك مشكلة صغيرة تواجهنا الآن 🙁 عندما نقوم بتنفيذ الأمر npm run dev فإنه لا يتم إنشاء أي ملف HTML داخل المجلد dist، رغم أننا قمنا بإنشاء الملف index.html في المجلد src. من الواضح إذن بأن Webpack لا يستطيع لوحده القيام بهذه المهمة. سنقوم بمساعدته بواسطة إضافة جديدة ( Plugin ) اسمها HTML Webpack Plugin.

تلاحظون كذلك أننا لم نقم باستدعاء أي ملف جافاسكريبت في الصفحة src/index.html 🙂 سنترك هذه المهمة أيضا للإضافة HTML Webpack Plugin التي سنقوم بتثبيها في مشروعنا حالا ؛)

بعد تثبيت إضافتنا الجديدة، سنقوم بإعداد Webpack لكي يقوم باستخدامها. هيا بنا إلى الملف webpack.config.js 🙂

في البداية قمنا بإنشاء متغير (كلاس) جديد HtmlWebpackPlugin انطلاقا من الحزمة html-webpack-plugin، ثم قمنا بإنشاء نموذج (Instance) من هذا الكلاس داخل المصفوفة plugins، وبعد ذلك قمنا بتمرير 3 معاملات :

  • hash : قمنا بتمرير true لهذا المعامل حتى يتم إضافة سلسلة حروف وأرقام عشوائية إلى نهاية اسم ملف الجافاسكريبت المحزم ( مثال:  main.js?3cbc8ec659d08ad396e1 ) عند استدعائه في الصفحة. يستخدم هذا ال Hash لأغراض تتعلق بالكاش Cache الخاص بالصفحة.
  • template : هذا المعامل يمثل مسار القالب الذي سيبنى عليه ملف HTML المُخرَج.
  • filename : اسم ملف HTMLالمُخرَج.

وهناك مجموعة من المعاملات الأخرى يمكنكم الإطلاع عليها في صفحة الإضافة على Github.

الآن، بعض تنفيذ npm run dev مرة أخرى سنرى بأن Webpack قام بإنشاء ملف index.html داخل المجلد dist مع استدعاء الملف main.js المحزم (Bundled).

لم ننتهي بعد! أين هو CSS ؟

لا يوجد تطبيق ويب من دون CSS، لنقم بإنشاء ملف style.css في المجلد src.

ثم لنقم باستدعائه من ملف index.js، نعم من الجافاسكريبت 😀

Webpack لا يستطيع التعامل مع ملفات CSS، فهو دائما ينتظر ملفات JavaScript. لهذا عند تشغيله سيظهر لنا هذا الخطأ الجميل والذي يخبرنا بأنه علينا مساعدة Webpack في إيجاد حل للتعامل مع ملفات CSS وذلك بتثبيت ال Loader المناسب لهذه الحالة.

ال Loader الذي نحتاجه هنا موجود واسمه css-loader، لنقم بتثبيته الآن :

هذا loader يمكن Webpack من استيراد أكواد CSS باستخدام import أو require، وهذه حدود دور css-loader، هذا الدور ضروري ولكنه غير كافي.

نحن الآن لدينا ال CSS المستورد بفضل css-loader، ولكن كيف نقوم باستدعاء هذا CSS في الصفحة ؟

لحسن الحظ هناك إضافة (Plugin) أخرى اسمها mini-css-extract-plugin وتمكن من استخلاص ال CSS المستورد ووضعه في ملف (أو ملفات) CSS منفصل.

لنقم بتثبيت هذه الإضافة :

بعد التثبيت، سنقوم بإعداد Webpack لكي يستعين بهذه الإضافة الجديدة :

مثلما فعلنا مع إضافة HtmlWebpackPlugin، قمنا بإنشاء نموذج من الكلاس MiniCssExtractPlugin وأضفناه في المصفوعة plugins، ثم طلبنا منه أن يكون اسم ملف ال CSS المخرج bundle.css. ولا ننسى كذلك أننا أعطينا تعليمات لِ Webpack من داخل المصفوفة rules لكي يقوم بإجراء css-loader و MiniCssExtractPlugin.loader (هذا الأخير يمكن تعويضه ب style-loader بعد تثبيته) على جميع الملفات من نوع css.

ومن الآن، بعد تشغيل Webpack سيتم استخلاص ال css المستورد من داخل الجافاسكريبت ويضاف إلى ملف جديد اسمه bundle.css في المجلد dist، ثم يتم استدعائه تلقائيا في الملف dist/index.html 🙂 إليكم الحالة النهائية لهذا الملف :

وفي الصورة التالية، تجدون البنية النهائية لمشروعنا :

النهاية

هكذا تعلمنا اليوم كيفية إضافة Webpack إلى مشاريعنا والإستعانة بالمزايا العديدة التي يوفرها بفضل العدد الكبير من Loaders و Plugins التي تزخر بها هذه البيئة.

المهام التي أنجزناها في هذا الدرس تعتبر بسيطة مقارنة بكل ما يمكن القيام به، حتى الإضافات و Loaders التي تطرقنا إليها اليوم لم نرى من إمكانياتها سوى القليل، فأدعوكم لزيارة صفحات كل واحدة منها على Github لإكتشاف جميع المزايا التي تقدمها.

لا تبخلوا علي بآرائكم حول هذه التقنية الرائعة، كما أدعوكم لطرح استفساراتكم وأسئلتكم حول هذا الموضوع في صندوق التعليقات أسفله، سأسعد كثيرا بالتواصل معكم 😀

7 تعليقات

  1. مقال راائع جدا و شرح موفق وأحب أن اوضح أن إمكانيات ويب باك لامحدودة فيمكن أيضا الاستعانة به في تحسين ضغط الصور لتصبح خفيفة التحميل.

    شكرا لك استاذ عيسى على المقال المتميز

    • شكرا لك كذلك صديقي سيداتي،
      يسرني أن تكون من متابعي مدونة توتومينا 😉

  2. شكراً على الإبداع منقطع النظير
    أرجو أن تضع لنا رابط github للمشروع في هذا المثال وفي كل الأمثلة المشابهة لاحقاً
    كل التحية والاحترام لك

ترك الرد

Please enter your comment!
Please enter your name here