أداء البناء
يحتوي هذا الدليل على بعض النصائح المفيدة لتحسين أداء البناء/الترجمة.
عام
ينبغي أن تساعد أفضل الممارسات التالية سواء كنت تشغّل سكربتات البناء في التطوير أو الإنتاج.
ابقَ محدّثًا
استخدم أحدث إصدار من webpack. نحن نعمل دائمًا على تحسينات في الأداء. أحدث إصدار موصى به من webpack هو:
يمكن أن يساعد البقاء محدّثًا مع Node.js أيضًا في الأداء. إضافة إلى ذلك، يمكن أن يساعد تحديث مدير الحزم لديك، مثل npm أو yarn. فالإصدارات الأحدث تُنشئ أشجار وحدات أكثر كفاءة وتزيد سرعة الحل.
Loaders
طبّق الـ loaders على أقل عدد ممكن من الوحدات الضرورية. بدلًا من:
export default {
// ...
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
},
],
},
};استخدم الحقل include لتطبيق الـ loader فقط على الوحدات التي تحتاج فعليًا إلى تحويله لها:
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
// ...
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, "src"),
loader: "babel-loader",
},
],
},
};بدء التشغيل
لكل loader أو plugin إضافي وقت بدء تشغيل. حاول استخدام أقل عدد ممكن من الأدوات.
الحل
يمكن للخطوات التالية زيادة سرعة الحل:
- قلّل عدد العناصر في
resolve.modulesوresolve.extensionsوresolve.mainFilesوresolve.descriptionFiles، لأنها تزيد عدد استدعاءات نظام الملفات. - اضبط
resolve.symlinks: falseإذا كنت لا تستخدم الروابط الرمزية، مثلnpm linkأوyarn link. - اضبط
resolve.cacheWithContext: falseإذا كنت تستخدم ملحقات حل مخصصة غير مرتبطة بسياق محدد.
Dlls
استخدم DllPlugin لنقل الكود الذي يتغير بوتيرة أقل إلى ترجمة منفصلة. سيحسّن ذلك سرعة ترجمة التطبيق، مع أنه يزيد تعقيد عملية البناء.
الأصغر = الأسرع
خفّض الحجم الإجمالي للترجمة لزيادة أداء البناء. حاول إبقاء الأجزاء صغيرة.
- استخدم مكتبات أقل أو أصغر.
- استخدم
SplitChunksPluginفي التطبيقات متعددة الصفحات. - استخدم
SplitChunksPluginفي وضعasyncداخل التطبيقات متعددة الصفحات. - أزل الكود غير المستخدم.
- ترجم فقط الجزء الذي تعمل على تطويره حاليًا من الكود.
تجمع العمال
يمكن استخدام thread-loader لنقل الـ loaders المكلفة إلى تجمع عمال.
التخزين المؤقت المستمر
استخدم خيار cache في إعداد webpack. امسح مجلد التخزين المؤقت في "postinstall" داخل package.json.
Plugins/Loaders مخصصة
حلّل أداءها حتى لا تضيف مشكلة أداء هنا.
ملحق التقدم
يمكن تقصير أزمنة البناء بإزالة ProgressPlugin من إعداد webpack. ضع في الحسبان أن ProgressPlugin قد لا يقدم قيمة كبيرة في البناءات السريعة أيضًا، لذلك تأكد من أنك تستفيد فعلًا من استخدامه.
التطوير
الخطوات التالية مفيدة خصوصًا في التطوير.
البناءات التزايدية
استخدم وضع المراقبة في webpack. لا تستخدم أدوات أخرى لمراقبة ملفاتك واستدعاء webpack. سيتتبع وضع المراقبة المدمج الطوابع الزمنية ويمرر هذه المعلومات إلى الترجمة لإبطال التخزين المؤقت.
في بعض الإعدادات، تعود المراقبة إلى وضع الاستطلاع. ومع وجود عدد كبير من الملفات المراقبة، قد يسبب ذلك حملًا كبيرًا على CPU. في هذه الحالات، يمكنك زيادة فاصل الاستطلاع باستخدام watchOptions.poll.
الترجمة في الذاكرة
تحسن الأدوات التالية الأداء عبر ترجمة الأصول وتقديمها من الذاكرة بدلًا من الكتابة على القرص:
webpack-dev-serverwebpack-hot-middlewarewebpack-dev-middleware
سرعة stats.toJson
يُخرج Webpack 4 كمية كبيرة من البيانات باستخدام stats.toJson() افتراضيًا. تجنب استرجاع أجزاء من كائن stats ما لم يكن ذلك ضروريًا في الخطوة التزايدية. احتوى webpack-dev-server بعد v3.1.3 على إصلاح أداء مهم لتقليل كمية البيانات المسترجعة من كائن stats في كل خطوة بناء تزايدية.
Devtool
كن واعيًا بفروق الأداء بين إعدادات devtool المختلفة.
- يملك
"eval"أفضل أداء، لكنه لا يساعدك مع الكود المحوّل. - متغيرات
cheap-source-mapأكثر أداء إذا كان بإمكانك قبول جودة ربط أقل قليلًا. - استخدم أحد متغيرات
eval-source-mapللبناءات التزايدية.
تجنب أدوات الإنتاج الخاصة
بعض الأدوات والملحقات والـ loaders لا تكون منطقية إلا عند البناء للإنتاج. على سبيل المثال، لا يكون تصغير الكود وتغيير أسمائه باستخدام MinimizerPlugin منطقيًا عادة أثناء التطوير. ينبغي غالبًا استبعاد هذه الأدوات في التطوير:
MinimizerPlugin[fullhash]/[chunkhash]/[contenthash]AggressiveSplittingPluginAggressiveMergingPluginModuleConcatenationPlugin
جزء إدخال صغير
لا يصدر webpack إلى نظام الملفات إلا الأجزاء المحدّثة. في بعض خيارات الإعداد، مثل HMR و[name]/[chunkhash]/[contenthash] في output.chunkFilename و[fullhash]، يُبطل جزء الإدخال بالإضافة إلى الأجزاء التي تغيرت.
تأكد من أن إصدار جزء الإدخال رخيص بإبقائه صغيرًا. ينشئ الإعداد التالي جزءًا إضافيًا لكود وقت التشغيل، لذلك يكون توليده رخيصًا:
export default {
// ...
optimization: {
runtimeChunk: true,
},
};تجنب خطوات التحسين الإضافية
ينفذ webpack عملًا خوارزميًا إضافيًا لتحسين الخرج من ناحية الحجم وأداء التحميل. هذه التحسينات ذات أداء جيد في قواعد الكود الأصغر، لكنها قد تكون مكلفة في القواعد الأكبر:
export default {
// ...
optimization: {
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false,
},
};الإخراج من دون معلومات المسار
لدى webpack القدرة على توليد معلومات المسار داخل الحزمة الناتجة. لكن ذلك يضع ضغطًا على جامع القمامة في المشاريع التي تجمع آلاف الوحدات. عطّل ذلك في الإعداد options.output.pathinfo:
export default {
// ...
output: {
pathinfo: false,
},
};إصدارات Node.js 8.9.10-9.11.1
كان هناك تراجع في الأداء في إصدارات Node.js من 8.9.10 إلى 9.11.1 في تطبيقات ES2015 لـ Map وSet. يستخدم webpack هياكل البيانات هذه بكثرة، لذلك يؤثر هذا التراجع في أزمنة الترجمة.
لا تتأثر إصدارات Node.js الأقدم أو الأحدث.
TypeScript Loader
لتحسين وقت البناء عند استخدام ts-loader، استخدم خيار loader المسمى transpileOnly. هذا الخيار يوقف فحص الأنواع بحد ذاته. لاستعادة فحص الأنواع، استخدم ForkTsCheckerWebpackPlugin. يسرّع ذلك فحص أنواع TypeScript وتدقيق ESLint بنقل كل منهما إلى عملية منفصلة.
export default {
// ...
test: /\.tsx?$/,
use: [
{
loader: "ts-loader",
options: {
transpileOnly: true,
},
},
],
};الإنتاج
الخطوات التالية مفيدة خصوصًا في الإنتاج.
خرائط المصدر
خرائط المصدر مكلفة جدًا. هل تحتاج إليها فعلًا؟
مشكلات أدوات محددة
تعاني الأدوات التالية من مشكلات معينة قد تضعف أداء البناء:
Babel
- قلّل عدد الـ preset/plugins.
TypeScript
- استخدم
fork-ts-checker-webpack-pluginلفحص الأنواع في عملية منفصلة. - اضبط الـ loaders لتخطي فحص الأنواع.
- استخدم
ts-loaderفيhappyPackMode: true/transpileOnly: true.
Sass
- تحتوي
node-sassعلى علة تمنع الخيوط من تجمع خيوط Node.js. عند استخدامها معthread-loaderاضبطworkerParallelJobs: 2.



