كيفية التبديل تدريجيا إلى webpack

هذا هو الجزء الثاني من سلسلة من جزأين حول لماذا وكيف قمنا بتحويل نظام حزم جافا سكريبت الخاص بنا من نظام مخصص من مهام Grunt و PHP ، إلى تكوين حزمة معلنة على الويب. انقر هنا للانتقال إلى سبب تحولنا إلى حزمة الويب لمعرفة سبب تحولنا إلى حزمة الويب.

هذه المقالة مناسبة لك إذا كان نظام بناء جافا سكريبت JavaScript الخاص بك مشفرًا يشبه مشاكلنا في "لماذا تحولنا إلى حزمة الويب" ، وتريد الانتقال إلى حزمة الويب بطريقة تدريجية عن طريق تقسيمها إلى خطوات أصغر. بعض أجزاء هذه المقالة خاصة بـ 1.x AngularJS ، ولكن يمكن تطبيق الباقي على أي إطار عمل.

لجعل عملية الترحيل غير مؤلمة قدر الإمكان ، قم بتقسيمها إلى الخطوات التالية:

  1. قم بتقديم حزمة الويب جنبًا إلى جنب مع نظام الإنشاء الحالي دون تغيير رمز التطبيق الخاص بك.
  2. استخدم حزمة الويب أثناء التطوير لفترة من الوقت ، وحل المشكلات فور ظهورها. إهمال استخدام نظام الإنشاء القديم ، لكن استمر في استخدامه في الإنتاج.
  3. إزالة نظام البناء المهملة ، مع ترك حزمة الويب فقط.
  4. قم بتحديث codebase مع التحسينات التي أصبحت ممكنة الآن مع webpack.

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

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

1. تقديم حزمة الويب إلى جانب نظام البناء الحالي الخاص بك

ابدأ بتكرار الميزات الأساسية لنظام البناء القديم اللازمة لإنشاء التطبيق الخاص بك:

  • إنشاء حزمة جافا سكريبت
  • إنشاء حزمة CSS
  • تقديم مسارات الأصول JS / CSS إلى قالب HTML الخاص بك

لاحظ أنه يمكنك استبعاد متطلبات أكثر تقدماً من هذه القائمة ، مثل التصغير أو تجميع اختبارات karma أو تجميع سلاسل اللغة المترجمة. يمكن التعامل مع هذه خلال الخطوة رقم 2.

إنشاء حزمة جافا سكريبت

من المحتمل أن يتضمن نظام الإنشاء الحالي الخاص بك خطوة سَلسَلة لدمج العديد من البرامج النصية في واحدة ، كما هو الحال مع grunt-المساهمة-concat:

grunt.initConfig ({
  concat: {
    شبيبة: {
      الملفات: [{
        src: [
          "بائع / lodash.js،
          "بائع / jquery.js،
          "بائع / angular.js،
          "بائع / الزاوي-cookies.js،
          "التطبيق / مخطوطات / ** / *. شبيبة"
        ]،
        dest: 'build / js /'
      }]
    }
  }
})؛

لحسن الحظ ، تعتبر حزمة الويب مرنة بدرجة كافية لتكرار هذا السلوك باستخدام محمل الواردات ، محمل الصادرات ، والسياق:

لجعل حزمة WebS JS الخاصة بك تتطابق مع حزمة البرامج النصية القديمة الخاصة بك ، قم بإنشاء ملف .js جديد للعمل كنقطة إدخال webpack ، واستخدم محمل الواردات و loader-loader لاستيراد التبعيات وقيم التصدير للبرامج النصية الخاصة بالمورد ، على سبيل المثال

// app / app.js
// استيراد البرامج النصية للبائع القديم بالترتيب الصحيح
window._ = مطلوب (
  "../vendor/lodash"
)؛
نافذة. $ = window.jQuery = تتطلب (
  "../vendor/jquery"
)؛
window.angular = تتطلب (
  صادرات؟ window.angular! ../ بائع / الزاوي '
)؛
تطلب(
  "واردات؟ الزاوي => window.angular! +
  "../vendor/angular-cookies"
)؛
// ... البرامج النصية التطبيق

نظرًا لأن كل برنامج نصي للمورد له تبعيات مختلفة وقيم مُصدرة ، يجب فحص كل منها يدويًا لتحديد ما إذا كان وكيفية استخدام محمل الواردات ومحمل التصدير. تأكد من تعيين المتغيرات العامة إلى "نافذة" للتأكد من توفرها في رمز التطبيق الخاص بك.

إذا كان يلزم أيضًا تنفيذ رمز التطبيق الخاص بك بترتيب معين ، فيمكنك ببساطة "طلب" كل ملف بالتسلسل ، على سبيل المثال

// app / app.js
// ... نصوص البائع
تتطلب ( './ مخطوطات / moduleA')؛
تتطلب ( './ مخطوطات / moduleB')؛
تتطلب ( './ مخطوطات / moduleC')؛
// ...
تتطلب ( './ مخطوطات / الرئيسية')؛

أو ، إذا كان يمكن تنفيذ رمز التطبيق الخاص بك بأي ترتيب (على سبيل المثال ، إذا كنت تستخدم وحدات AngularJS) ، فيمكنك الاستفادة من سياق حزمة الويب `` `` `` `لجميع هذه الملفات في وقت واحد:

// app / app.js
// ... نصوص البائع
/ **
 * `تتطلب` جميع الوحدات النمطية في سياق webpack معين
 * /
وظيفة requireAll (السياق) {
  context.keys () forEach (السياق)؛
}
/ / جمع كل الوحدات الزاوي
requireAll (require.context (
  "./scripts،
  / * استخدم الدلائل الفرعية: * / true ،
))؛

للتعامل مع ملفات JS الخاصة بك ، هذا كل ما في الأمر! لا يلزم إجراء تغييرات على البرامج النصية للبائع أو رمز التطبيق ؛ تحتاج فقط إلى تعديل نقطة دخول webpack. من المهم ألا تقوم بتعديل رمز التطبيق نفسه ، لضمان أنه يمكنك الاستمرار في البناء باستخدام نظام البناء السابق.

إنشاء حزمة CSS

من المحتمل أن تتضمن خطوة إنشاء CSS الخاصة بك خطوة ما قبل المعالجة ، مثل مع Stylus عبر القلم-المساهم-stylus:

grunt.initConfig ({
  القلم: {
    ترجمة: {
      الملفات: {
        src: 'app / css / main.styl' ،
        dest: 'build / css / main.css'
      }
    }
  }
})؛

يقدم webpack مجموعة من اللوادر للتعامل مع المعالجة والإخراج المسبق لـ CSS:

  • stylus-loader / sass-loader / less-loader: يقوم بتشغيل المعالج المسبق المحدد على ملف (ملفات) CSS الخاص بك ، مع إرجاع CSS العادي
  • css-loader: يحل `@ import` /` url (…) `ويعيد CSS الناتج
  • url-loader / file-loader: مضمنة أو تنبعث من محتويات الملف في إخراج webpack ، مثل الخط أو الصورة `url (...) في CSS
  • extract-text-webpack-plugin: ينقل CSS إلى ملف إخراج منفصل ، بدلاً من تضمينه في HTML

يتم ترك تكوين حزمة الويب مع هذه اللوادر كتمرين للقارئ ، ولكن بمجرد تكوينه ، تكون إضافة ورقة الأنماط الخاصة بك إلى حزمة webpack بسيطة مثل إضافة `طلب (...)` إلى نقطة الإدخال:

// app / app.js
تتطلب ( './ المغلق / main.styl')؛
// ... نصوص البائع
// ... البرامج النصية التطبيق

ملاحظة: لا يلزم بالضرورة أن تكون خطوة إنشاء CSS جزءًا من webpack build ؛ على سبيل المثال ، كان بإمكاننا اختيار التبديل إلى برنامج نصي بسيط في npm يستدعي الأمر `stylus`. لكننا نحصل على بعض الفوائد باستخدام webpack:

  • يجب تشغيل حزمة الويب فقط لإنشاء JS و CSS ؛ لا حاجة لتشغيل أمر منفصل لبناء CSS.
  • يتم إدراج أصول الصور / الخطوط المشار إليها في CSS تلقائيًا في إخراج webpack ؛ لا حاجة لنسخها إلى مجلد الإخراج وإدارة مسارات الأصول عبر طريقة أخرى.
  • سوف يولد file-loader تلقائيًا أسماء ملفات التجزئة للتخزين المؤقت طويل المدى لملف CSS والخطوط / الصور المضمنة.

تقديم مسارات الأصول JS / CSS إلى قالب HTML الخاص بك

الخطوة الأخيرة لتكون قادراً على تشغيل كل من webpack ونظام البناء القديم الخاص بك على نفس قاعدة البيانات هي تقديم أصول webpack JS / CSS الجديدة إلى قالب HTML لموقعك.

يمكنك التقاط مسارات جميع أصول مخرجات webpack باستخدام كائن "الإحصائيات" الذي يتم إرجاعه عند اكتمال البناء. طريقة بسيطة لتمرير تلك البيانات إلى قالب HTML الخاص بك هي عبر stats-webpack-plugin:

// webpack.config.js
const StatsPlugin = require ('stats-webpack-plugin') ؛
module.exports = {
  // ...
  الإضافات: [
    // ...
    StatsPlugin الجديدة ('webpack-stats.json' ، {
      قطع: كاذبة ،
      وحدات: كاذبة ،
      الأطفال: خطأ ،
      نسخة مخبأة مؤقتًا: خطأ ،
      الأسباب: خطأ ،
      المصدر: خطأ ،
      errorDetails: false ،
      chunkOrigins: false ،
    })
  ]
}؛

للتبديل ذهابًا وإيابًا بسهولة بين حزمة الويب ونظام الإنشاء القديم ، يمكنك ببساطة تقديم مسارات أصول حزمة الويب إذا كان webpack-stats.json موجودًا في مجلد الإخراج الخاص بك ، وإلا يمكنك الرجوع إلى مسارات أصول نظام الإنشاء القديم.

على سبيل المثال ، باستخدام PHP:

هذه هي كل القطع اللازمة للحصول على الحد الأدنى من بناء webpack العمل! في هذه المرحلة ، يجب أن يكون مشروعك في هذه الحالة:

  • شغّل خطوة الإنشاء القديمة (على سبيل المثال `grunt build`) ، والتي ستنشئ أصول JS / CSS في مجلد الإنشاء الخاص بك ، مما يتسبب في جعل قالب HTML لموقعك يعرض مسارات الأصول بالطريقة القديمة.
  • قم بتشغيل `webpack` ، التي ستنشئ أصول JS / CSS و webpack-stats.json في مجلد البناء الخاص بك ، مما يتسبب في جعل قالب HTML لموقعك يعرض مسارات الأصول باستخدام webpack-stats.json.

2. استخدم حزمة الويب أثناء التطوير وإهمال استخدام نظام الإنشاء القديم

خلال هذه المرحلة ، أخبر المطورين الآخرين في المشروع باستخدام حزمة الويب بدلاً من نظام الإنشاء القديم. إذا ظهرت أي مشاكل (مثل اللودر الذي تم تكوينه بشكل خاطئ) ، فيمكنك حلها بأمان دون التأثير على الإنتاج ، حيث يستمر الإنتاج في استخدام نظام الإنشاء القديم في الوقت الحالي.

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

إذا كنت تستخدم عداءًا للمهام مثل Grunt أو Gulp ، فغالبًا ما تكون البرامج النصية npm بديلاً أبسط لمهام Grunt / Gulp.

فيما يلي بعض بدائل مهام Grunt التي نستخدمها:

  • grunt-karma: واجهة سطر أوامر Karma ("بداية karma")
  • grunt-angular-gettext: الزاوي gettext-cli + الزاوي gettext-loader
  • grunt-angular-templates: ngtemplate-l0ader

في نهاية هذه المرحلة ، يجب أن يكون لديك:

  • برنامج نصي npm لاستبدال كل مهمة بناء ، على سبيل المثال 'npm run bundle: watch` to bundle & watch أثناء التطوير' `npm run package: production` to package & minification with translation translation،` npm run karma` لإجراء اختبارات Karma
  • اختبر التطبيق بالكامل بالكامل للتأكد من أنه يعمل بشكل صحيح: احترس من البرامج النصية أو أوراق الأنماط المفقودة حيث إنها قد تؤدي إلى تعطل التطبيق.

3. إزالة نظام البناء المهملة ، وترك فقط webpack

هذا الجزء سهل: ما عليك سوى تهيئة النص البرمجي CI build الخاص بك لتشغيل البرامج النصية الجديدة لبناء npm (مثل `npm test && npm run package: production`) ، وحذف تهيئة عداء المهام القديمة (Gruntfile.js / gulpfile.js / إلخ) ، وإزالة التبعيات غير المستخدمة الآن من package.json.

ستحتاج أيضًا إلى حذف الشفرة في قالب HTML الخاص بك والتي تعود إلى نظام الإنشاء القديم إذا لم تكن webpack-stats.json موجودة.

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

4. قم بتحديث قاعدة الكود مع التحسينات الممكّنة بواسطة webpack

الآن بعد أن أصبحت webpack هي نظام البناء الوحيد المعمول به ، يمكننا معالجة المشكلات الموضحة أصلاً في "لماذا تحولنا إلى حزمة الويب":

حل التبعيات

تذكر كيف تقوم بإعداد نقطة إدخال حزمة الويب لاستيراد البرامج النصية على مستوى العالم ، بالترتيب الأول من التبعية؟

// app / app.js
تتطلب ( './ المغلق / main.styl')؛
// استيراد البرامج النصية للبائع القديم بالترتيب الصحيح
window._ = مطلوب (
  "../vendor/lodash"
)؛
// ...
تتطلب ( './ مخطوطات / moduleA')؛
تتطلب ( './ مخطوطات / moduleB')؛
تتطلب ( './ مخطوطات / moduleC')؛
// ...
تتطلب ( './ مخطوطات / الرئيسية')؛

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

بدلاً من ذلك ، يمكنك الآن استيراد التبعيات في الوحدة النمطية حيث يتم استخدامها ، على سبيل المثال إذا كان main.js يعتمد على lodash.js و moduleA.js و moduleC.js:

// التطبيق / البرامج النصية / main.js
var _ = require ('../../ vendor / lodash') ؛
var A = require ('./ moduleA') ؛
var C = require ('./ moduleC') ؛
// ...

وإذا كان moduleB.js يعتمد فقط على moduleA.js:

// التطبيق / البرامج النصية / moduleB.js
var A = require ('./ moduleA') ؛
// ...

بمجرد أن يتم استيراد وحدة نمطية بشكل صريح من قبل جميع المعالين لها ، يمكن إزالتها من نقطة إدخال حزمة الويب: نقل وحدة نمطية واحدة في كل مرة ، وفي نهاية المطاف ستترك نقطة إدخال حزمة الويب الخاصة بك فقط:

// app / app.js
تتطلب ( './ المغلق / main.styl')؛
تتطلب ( './ مخطوطات / الرئيسية')؛

باستخدام حزم npm

يمكنك الآن البدء في استخدام حزم npm بدلاً من نسخ الوحدات النمطية للموردين الخارجيين إلى المستودع: تصبح ترقية الحزم أسهل ، والتبعيات المشتركة العابرة تقلل من ازدواجية التعليمات البرمجية ، ولم تعد بحاجة إلى إنشاء حزم UMD مخصصة.

يجب أن يكون الأمر بسيطًا مثل إجراء "تثبيت npm" "، ثم تحديث المراجع إلى الوحدة ، على سبيل المثال غير هذا:

var _ = require ('../../ vendor / lodash') ؛

الى هذا:

var _ = require ('lodash') ؛

الآن بعد أن أصبحت التبعيات صريحة ونستخدم حزم npm ، فقد حققنا (على الأقل إلى حد ما) هدف جعل قاعدة الأكواد أسهل في الفهم. كما قمنا بتحسين تعادل dev-prod أيضًا ، نظرًا لأن webpack يتعامل الآن مع تبعيات الوحدة النمطية لدينا بنفس الطريقة في كل من التطوير والإنتاج: والفرق الوحيد هو أن تصميم الإنتاج يتم تصغيره.

بالطبع ، جعلنا قاعدة الشفرة جاهزة للمستقبل حيث من الأسهل البدء في استخدام ES2015 + من خلال تشغيل بابل ، واستخدام React و Redux يصبحان أسهل مع القدرة على استخدام حزم JSX و npm.

كان هذا الانتقال قد نجح مؤخرًا في إنشاء قاعدة بيانات تطبيق الأحداث الأساسية لـ EventMobi. إذا كان مشروعك في حالة مماثلة ، آمل أن يكون هذا قد قدم بعض الأفكار حول كيفية تحسينه!

[إذا كنت تحب هذه المقالة ، فانقر فوق الزر الموجود على اليسار حتى يعرف الآخرون. إذا كنت تريد المزيد من المنشورات مثل هذا ، فاتبع منشور EventMobi مع زر (متابعة) على اليمين!

أخيرًا ، إذا كانت حل مثل هذه المشكلات تبدو مرتفعة ، فنحن نوظف! راجع مراكزنا المفتوحة الحالية على http://www.eventmobi.com/careers/]