من v4 إلى v5

يهدف هذا الدليل إلى مساعدتك على الترقية إلى webpack 5 عندما تستخدم webpack مباشرة. إذا كنت تستخدم أداة أعلى مستوى لتشغيل webpack، فارجع إلى تلك الأداة لمعرفة تعليمات الترقية.

التحضيرات

يتطلب Webpack 5 إصدار Node.js 10.13.0 على الأقل (LTS)، لذلك تأكد من ترقية Node.js إذا كنت ما زلت تستخدم إصدارًا أقدم.

ترقية webpack 4 وplugins/loaders الخاصة به

  1. رقّ webpack 4 إلى أحدث إصدار متاح.

    • عند استخدام webpack >= 4، لا ينبغي أن تحتاج الترقية إلى أحدث إصدار من webpack 4 إلى إرشادات إضافية.

    • إذا كنت تستخدم إصدار webpack أقل من 4، فراجع دليل الترقية إلى webpack 4.

  2. رقّ webpack-cli إلى أحدث إصدار متاح عند استخدامه.

  3. رقّ كل Plugins وLoaders المستخدمة إلى أحدث إصدار متاح.

    قد يكون لبعض Plugins وLoaders إصدار beta يجب استخدامه ليكون متوافقًا مع webpack 5. تأكد من قراءة release notes لكل plugin/loader عند ترقيته؛ فقد يدعم أحدث إصدار webpack 5 فقط ويفشل مع v4. في هذه الحالة، يُنصح بالتحديث إلى أحدث إصدار يدعم webpack 4.

Codemods

للمساعدة في الترقية من webpack v4 إلى v5، يوفر Codemod codemods مجتمعية مفتوحة المصدر يمكنها أتمتة معظم عملية الترقية.

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

شغّل webpack v5 migration codemods:

npx codemod@latest webpack/v5/migration-recipe

سيشغّل هذا codemods التالية من Codemod registry:

كل واحد من هذه codemods يؤتمت تغييرًا مذكورًا في دليل الترقية إلى webpack v5. للقائمة الكاملة من codemods المتاحة لـ webpack v5، راجع Codemod Registry.

تأكد من أن build لا يحتوي على أخطاء أو تحذيرات

قد تظهر أخطاء أو تحذيرات جديدة بسبب الإصدارات المحدثة من webpack وwebpack-cli وPlugins وLoaders. انتبه لتحذيرات deprecation أثناء build.

يمكنك تشغيل webpack بهذه الطريقة للحصول على stack traces لتحذيرات deprecation ومعرفة Plugins وLoaders المسؤولة عنها.

node --trace-deprecation node_modules/webpack/bin/webpack.js

لأن webpack 5 يزيل كل الميزات المهملة، تأكد من عدم وجود تحذيرات deprecation من webpack أثناء build قبل المتابعة.

تأكد من استخدام mode

اضبط mode على production أو development للتأكد من تطبيق defaults المناسبة.

حدّث الخيارات القديمة

حدّث الخيارات التالية إلى صيغتها الجديدة إذا كنت تستخدمها:

  • optimization.hashedModuleIds: trueoptimization.moduleIds: 'hashed'
  • optimization.namedChunks: trueoptimization.chunkIds: 'named'
  • optimization.namedModules: trueoptimization.moduleIds: 'named'
  • NamedModulesPluginoptimization.moduleIds: 'named'
  • NamedChunksPluginoptimization.chunkIds: 'named'
  • HashedModuleIdsPluginoptimization.moduleIds: 'hashed'
  • optimization.noEmitOnErrors: falseoptimization.emitOnErrors: true
  • optimization.occurrenceOrder: trueoptimization: { chunkIds: 'total-size', moduleIds: 'size' }
  • optimization.splitChunks.cacheGroups.vendorsoptimization.splitChunks.cacheGroups.defaultVendors
  • optimization.splitChunks.cacheGroups.test(module, chunks)optimization.splitChunks.cacheGroups.test(module, { chunkGraph, moduleGraph })
  • Compilation.entriesCompilation.entryDependencies
  • serve → تمت إزالة serve لصالح DevServer
  • Rule.query (مهمل منذ v3) → Rule.options/UseEntry.options
  • Rule.loadersRule.use

اختبر توافق webpack 5

جرّب ضبط الخيارات التالية داخل إعداد webpack 4 لديك وتحقق من أن build ما زال يعمل بشكل صحيح.

export default {
  // ...
  node: {
    Buffer: false,
    process: false,
  },
};

يجب إزالة هذه الخيارات مرة أخرى عند ترقية إعدادك إلى webpack 5.

ترقية webpack إلى 5

الآن لنرقّ webpack إلى الإصدار 5:

  • npm: npm install webpack@latest

  • Yarn: yarn add webpack@latest

  • pnpm: pnpm add webpack@latest

إذا لم تستطع ترقية بعض plugins/loaders إلى أحدث إصدار في خطوة ترقية webpack 4 وplugins/loaders الخاصة به، فلا تنس ترقيتها الآن.

تنظيف الإعدادات

  • فكر في إزالة optimization.moduleIds وoptimization.chunkIds من إعدادات webpack. قد تكون defaults أفضل، لأنها تدعم long term caching في production mode وdebugging في development mode.

  • إذا كنت تستخدم placeholder [hash] في إعدادات webpack، ففكر في تغييره إلى [contenthash]. ليسا الشيء نفسه، لكن [contenthash] أثبت أنه أكثر فعالية.

  • إذا كنت تستخدم Yarn PnP وpnp-webpack-plugin، فهناك خبر جيد: أصبح مدعومًا افتراضيًا الآن. يجب إزالته من الإعدادات.

  • إذا كنت تستخدم IgnorePlugin مع regular expression كـ argument، فهو الآن يأخذ كائن options: new IgnorePlugin({ resourceRegExp: /regExp/ }).

  • إذا كنت تستخدم شيئًا مثل node.fs: 'empty' فاستبدله بـ resolve.fallback.fs: false.

  • إذا كنت تستخدم watch: true في webpack Node.js API، فأزله. لا حاجة لضبطه لأنه يُفهم من دالة compiler التي تستدعيها، إما true عند watch() أو false عند run().

  • إذا كانت لديك rules لتحميل assets باستخدام raw-loader أو url-loader أو file-loader، فاستخدم Asset Modules بدلًا منها لأنها ستُهمل في المستقبل القريب.

  • إذا كان target لديك مضبوطًا على دالة، فحدّثه إلى false وطبّق تلك الدالة داخل خيار plugins. راجع المثال:

    // في webpack 4
    {
        target: WebExtensionTarget(nodeConfig)
    }
    
    // في webpack 5
    {
        target: false,
        plugins: [
            WebExtensionTarget(nodeConfig)
        ]
    }

    ملاحظة: يوجد Codemod لهذا التغيير:

    npx codemod webpack/v5/set-target-to-false-and-update-plugins

    (راجع registry هنا.)

  • إذا كان لديك output.library أو output.libraryTarget، فغيّر أسماء الخصائص: output.libraryTarget تصبح output.library.type، وoutput.library تصبح output.library.name. مثال:

    // في webpack 4
    {
        output: {
          library: 'MyLibrary',
          libraryTarget: 'commonjs2'
        }
    }
    
    // في webpack 5
    {
        output: {
          library: {
            name: 'MyLibrary',
            type: 'commonjs2'
          }
        }
    }

    ملاحظة: يوجد Codemod لهذا التغيير:

    npx codemod webpack/v5/migrate-library-target-to-library-object

    (راجع registry هنا.)

إذا كنت تستخدم WebAssembly عبر import، فاتبع هذه العملية من خطوتين:

  • فعّل المواصفة المهملة بضبط experiments.syncWebAssembly: true للحصول على السلوك نفسه الموجود في webpack 4.
  • بعد نجاح الترقية إلى webpack 5، غيّر قيمة experiments إلى experiments: { asyncWebAssembly: true } لاستخدام المواصفة الأحدث لتكامل WASM.

أعد التفكير في optimization.splitChunks:

  • يُنصح باستخدام defaults أو optimization.splitChunks: { chunks: 'all' }.
  • عند استخدام إعداد مخصص، احذف name: false واستبدل name: string | function بـ idHint: string | function.
  • كان ممكنًا تعطيل defaults بضبط optimization.splitChunks.cacheGroups: { default: false, vendors: false }. لا نوصي بذلك، لكن إذا كنت تريد الأثر نفسه في webpack 5: استخدم optimization.splitChunks.cacheGroups: { default: false, defaultVendors: false }.

فكر في إزالة defaults:

  • عند استخدام entry: './src/index.js': يمكنك حذفها، لأنها القيمة الافتراضية.
  • عند استخدام output.path: path.resolve(__dirname, 'dist'): يمكنك حذفها، لأنها القيمة الافتراضية.
  • عند استخدام output.filename: '[name].js': يمكنك حذفها، لأنها القيمة الافتراضية.

هل تحتاج إلى دعم متصفح قديم مثل IE 11؟

  • إذا كان browserslist مفعّلًا في مشروعك، فسيعيد webpack 5 استخدام إعداد browserslist لتحديد أسلوب الكود الذي سيصدره runtime.

    تأكد من:

    1. ضبط target على browserslist أو حذف target وترك webpack يضبط browserslist تلقائيًا.
    2. إضافة IE 11 إلى إعداد browserslist لديك.
  • بدون browserslist، يستخدم runtime code الخاص بـ webpack صيغة ES2015، مثل arrow function، لإنتاج bundles أصغر. لذلك ستحتاج إلى ضبط target: ['web', 'es5'] لاستخدام صيغة ES5 للمتصفحات التي لا تدعم ES2015 مثل IE11.

  • بالنسبة إلى Node.js، تتضمن builds إصدار Node.js المدعوم داخل خيار target، وسيعرف webpack تلقائيًا أي syntax مدعوم، مثل target: 'node8.6'.

تنظيف الكود

استخدام /* webpackChunkName: '...' */

تأكد من فهم الهدف:

  • اسم chunk هنا مقصود أن يكون عامًا.
  • ليس اسمًا خاصًا بالتطوير فقط.
  • سيستخدمه webpack لتسمية الملفات في production وdevelopment modes.
  • سيعين webpack 5 أسماء ملفات مفيدة تلقائيًا في development mode حتى بدون استخدام webpackChunkName.

استخدام named exports من JSON modules

هذا غير مدعوم في المواصفة الجديدة وستحصل على تحذير. بدلًا من:

import { version } from "./package.json";

console.log(version);

استخدم:

import pkg from "./package.json";

console.log(pkg.version);

ملاحظة: يوجد Codemod لهذا التغيير:

npx codemod webpack/v5/json-imports-to-default-imports

(راجع registry هنا.)

تنظيف كود build

  • عند استخدام const compiler = webpack(...);، تأكد من إغلاق compiler بعد استخدامه: compiler.close(callback);.
    • لا ينطبق هذا على صيغة webpack(..., callback) لأنها تُغلق تلقائيًا.
    • هذا اختياري إذا كنت تستخدم webpack في watching mode حتى ينهي المستخدم العملية. ستُستخدم idle phases في watch mode لهذا النوع من العمل.

شغّل build واحدًا واتبع النصائح

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

كرر الخطوات التالية حتى تحل المستوى 3 أو 4 على الأقل:

  • المستوى 1: فشل Schema validation.

    تغيرت خيارات الإعداد. يجب أن يظهر validation error يحتوي على ملاحظة BREAKING CHANGE:، أو تلميح للخيار الذي يجب استخدامه بدلًا من القديم.

  • المستوى 2: ينهي Webpack العمل بخطأ.

    يجب أن تخبرك رسالة الخطأ بما يحتاج إلى تغيير.

  • المستوى 3: Build Errors.

    يجب أن تحتوي رسالة الخطأ على ملاحظة BREAKING CHANGE:.

  • المستوى 4: Build Warnings.

    يجب أن تخبرك رسالة التحذير بما يمكن تحسينه.

  • المستوى 5: Runtime Errors.

    هذا أصعب. غالبًا ستحتاج إلى debugging لمعرفة المشكلة. تقديم نصيحة عامة هنا صعب، لكن هذه بعض النصائح الشائعة المتعلقة بـ Runtime Errors:

    • process غير معرّف.
      • لم يعد webpack 5 يضيف polyfill لهذا المتغير الخاص بـ Node.js. تجنب استخدامه في كود frontend.
      • تريد دعم الاستخدام في المتصفح؟ استخدم حقلي exports أو imports داخل package.json لاختيار كود مختلف حسب البيئة.
        • استخدم أيضًا حقل browser لدعم bundlers القديمة.
        • بديل آخر: غلّف أجزاء الكود بفحوصات typeof process. لاحظ أن هذا يؤثر سلبًا في حجم bundle.
      • تريد استخدام environment variables عبر process.env.VARIABLE؟ تحتاج إلى استخدام DefinePlugin أو EnvironmentPlugin لتعريف هذه المتغيرات في الإعدادات.
        • فكر في استخدام VARIABLE بدلًا من ذلك، وتأكد من فحص typeof VARIABLE !== 'undefined' أيضًا. process.env خاص بـ Node.js ويجب تجنبه في كود frontend.
    • أخطاء 404 تشير إلى URLs تحتوي على auto.
      • ليست كل أدوات ecosystem جاهزة للقيمة الافتراضية الجديدة للـ publicPath التلقائي عبر output.publicPath: "auto".
        • استخدم output.publicPath: "" ثابتًا بدلًا من ذلك.
    • Cannot read properties of undefined (reading 'call')
      • إذا رأيت هذا الخطأ وقت runtime، فقد يكون مرتبطًا بـ ModuleConcatenationPlugin. تحقق مما إذا كنت تستخدم plugin، وإذا كنت أضفته إلى قسم plugins في إعداد ما وكان ذلك الإعداد مضبوطًا أيضًا على production mode، فأزل plugin، أي new webpack.optimize.ModuleConcatenationPlugin()، من قائمة plugins. في webpack 5، هذا plugin مفعّل افتراضيًا في production mode، وقد تتم إضافته مرتين.
      • بشكل عام، تعطيل كل plugin واختبار build طريقة جيدة لتحديد مصدر المشكلة.
      • راجع هذه المناقشة لمزيد من التفاصيل.
  • المستوى 6: Deprecation Warnings.

    غالبًا ستظهر لك تحذيرات deprecation كثيرة. هذا ليس مشكلة مباشرة. تحتاج plugins وقتًا للحاق بتغييرات core. يرجى إبلاغ مؤلفي plugins بهذه التحذيرات. هذه التحذيرات مجرد warnings وسيظل build يعمل مع عيوب بسيطة فقط، مثل أداء أقل.

    • يمكنك إخفاء تحذيرات deprecation بتشغيل node مع flag --no-deprecation، مثل: node --no-deprecation node_modules/webpack/bin/webpack.js. يجب أن يكون هذا حلًا مؤقتًا فقط.
    • يمكن لمساهمي Plugins وLoaders اتباع النصائح الموجودة في رسائل deprecation لتحسين الكود.
  • المستوى 7: مشاكل الأداء.

    عادةً يجب أن يتحسن الأداء مع webpack 5، لكن توجد حالات قليلة قد يسوء فيها الأداء.

    وهذه أشياء يمكنك فعلها لتحسين الوضع:

    • اعمل profile لمعرفة أين يذهب الوقت.
      • يعرض --profile --progress الآن profile أداء بسيطًا.
      • استخدم node --inspect-brk node_modules/webpack/bin/webpack.js مع chrome://inspect أو edge://inspect، ثم راجع تبويب profiler.
        • يمكنك حفظ هذه profiles كملفات وإرفاقها في issues.
        • جرّب استخدام flag --no-turbo-inlining للحصول على stack traces أفضل في بعض الحالات.
    • يمكن تحسين وقت بناء modules في incremental builds بالرجوع إلى unsafe caching كما في webpack 4:
      • module.unsafeCache: true
      • لكن هذا قد يؤثر في القدرة على التعامل مع بعض تغييرات code base.
    • Full build
      • طبقة التوافق مع الميزات المهملة غالبًا أبطأ من الميزات الجديدة.
      • إنشاء warnings كثيرة قد يؤثر في أداء build حتى لو تم تجاهلها.
      • Source Maps مكلفة. راجع خيار devtool في التوثيق للمقارنة بين الخيارات المختلفة.
      • حماية Anti-Virus قد تؤثر في أداء الوصول إلى نظام الملفات.
      • Persistent Caching يمكن أن يساعد في تحسين full builds المتكررة.
      • Module Federation يسمح بتقسيم التطبيق إلى عدة builds أصغر.

كل شيء يعمل؟

يرجى التغريد بأنك نجحت في الترقية إلى webpack 5. غرّد بذلك

لا يعمل؟

أنشئ issue وأخبرنا بالمشاكل التي واجهتها أثناء الترقية.

يوجد شيء ناقص في هذا الدليل؟

افتح Pull Request لمساعدة الشخص التالي الذي يستخدم هذا الدليل.

تغييرات داخلية

التغييرات الداخلية في webpack، مثل إضافة الأنواع وإعادة هيكلة الكود وإعادة تسمية الدوال، مذكورة هنا لمن يهمه الأمر. لكنها ليست جزءًا من سيناريو الترقية المعتاد.

  • لم تعد Module.nameForCondition وModule.updateCacheModule وModule.chunkCondition اختيارية.

دالة getOptions للـ Loaders

يأتي Webpack 5 بدالة this.getOptions مدمجة ومتاحة داخل loader context. هذا تغيير كاسر للـ loaders التي كانت تستخدم دالة getOptions من schema-utils، والتي كانت مفضلة سابقًا:

  • this.getOptions متاحة منذ webpack 5.
  • بدل JSON5، تدعم JSON كـ query string: ?{arg:true}?{"arg":true}. يجب اعتبار استخدام JSON5 مهملًا وتوثيقه كذلك داخل توثيق loader المعني لصالح JSON.
  • لدى loader-utils سلوك خاص في تحليل query strings، حيث لا تُقرأ true وfalse وnull كنصوص بل كقيم primitive. لم يعد هذا هو الحال في دالة this.getOptions المدمجة الجديدة، فهي تستخدم تحليل querystring الأصلي من Node.js. ما زال بإمكانك إضافة سلوك مخصص لهذه الحالات داخل كود loader بعد الحصول على options باستخدام this.getOptions.
  • argument الخاص بـ schema اختياري في دالة this.getOptions الجديدة، لكننا ننصح بشدة بإضافة schema validation لخيارات loader. يمكن استخدام حقل title في schema لتخصيص رسالة خطأ validation. مثلًا "title": "My Loader ooooptions" سيؤدي إلى عرض الأخطاء بهذا الشكل: Invalid ooooptions object. My Loader has been initialised using an ooooptions object that does not match the API schema. - ooooptions.foo.bar.baz should be a string.
·تعديل هذه الصفحة
السابق ›
الترقية
‹ التالي
من v3 إلى v4

1 مساهم

RlxChap2