Webpack 5.106
يقدم Webpack 5.106 خطافات (hooks) للتحقق من صحة الإضافات (plugins)، وحقن نمط مدمج في وقت التشغيل (runtime) لـ CSS Modules، و tree shaking أذكى لتفكيك CommonJS (destructuring)، واستيرادات مرحلة المصدر (source-phase) لوحدات WebAssembly، وتكاملًا تجريبيًا مع oxc-parser لتحليل JavaScript أسرع.
اكتشف ما هو الجديد في هذا الإصدار:
- التحقق من صحة الإضافات باستخدام
compiler.hooks.validate - CSS Modules مع حقن النمط في وقت التشغيل
- Tree Shaking أفضل لتفكيك CommonJS
- استيرادات مرحلة المصدر لـ WebAssembly (تجريبي)
- البدء مع
create-webpack-app - دعم السياق لـ VirtualUrlPlugin
- تحليل JavaScript تجريبي باستخدام
oxc-parser - تحديثات النظام البيئي
- إصلاحات الأخطاء
التحقق من صحة الإضافات باستخدام compiler.hooks.validate
يضيف Webpack خيارًا جديدًا في المستوى الأعلى يسمى validate وخطافًا (hook) compiler.hooks.validate يوحدان كيفية عمل التحقق من المخطط (schema validation) عبر تكوين webpack، والإضافات، والمحملات (loaders).
حتى الآن، لم تكن هناك طريقة موحدة للإضافات لدمج التحقق من المخطط في دورة حياة بناء webpack. كانت كل إضافة تعالج التحقق بمفردها. يمنح خطاف compiler.hooks.validate الجديد مؤلفي الإضافات واجهة برمجة تطبيقات (API) قياسية لتسجيل منطق التحقق الخاص بهم، و compiler.validate(...) لتشغيله. وهذا يعني أن جميع عمليات التحقق من تكوين webpack الأساسي إلى كل إضافة تتبنى الخطاف يتم التحكم فيها بواسطة علامة validate واحدة وتتبع نفس الأنماط:
module.exports = {
// تعطيل التحقق من المخطط (تكوين webpack والإضافات والمحملات)
validate: false,
};تعتمد القيمة الافتراضية على وضع البناء:
| Mode | experiments.futureDefaults | الافتراضي لـ validate |
|---|---|---|
| development | false | true |
| development | true | true |
| production | false | true |
| production | true | false |
بالنسبة لمؤلفي الإضافات، يعد دمج التحقق أمرًا مباشرًا. قم بتسجيل tap على compiler.hooks.validate، وسيهتم webpack بالباقي، بما في ذلك تخطي التحقق تمامًا عندما يضبط المستخدم validate: false:
class MyPlugin {
constructor(options = {}) {
this.options = options;
}
apply(compiler) {
compiler.hooks.validate.tap("MyPlugin", () => {
compiler.validate(
() => require("./schema/MyPlugin.json"),
this.options,
{ name: "My Plugin", baseDataPath: "options" },
(options) => require("./schema/MyPlugin.check")(options),
);
});
// ...المنطق العادي للإضافة هنا...
}
}
module.exports = MyPlugin;عندما يكون validate true وهناك خطأ ما، يرمي webpack خطأً واضحًا في وقت التحويل البرمجي (compile time).
عندما يكون validate false، يتم تخطي هذا التحقق بالكامل. قد لا يزال البناء يفشل لاحقًا بخطأ أقل وضوحًا، لذا استخدم هذا الخيار بحذر.
CSS Modules مع حقن النمط في وقت التشغيل
يدعم Webpack الآن exportType: "style" لـ CSS Modules (عند تفعيل experiments.css: true)، مما يسمح بحقن CSS في DOM كـ <style> (HTMLStyleElement) مباشرة من وقت تشغيل webpack. يغطي هذا حالة الاستخدام النموذجية لـ style-loader، لذا لم يعد من الضروري استخدام style-loader لحقن الأنماط عند استخدام هذا الوضع.
بالإضافة إلى ذلك، يتم الاحتفاظ بصادرات CSS Module (على سبيل المثال، تعيين اسم الفئة (class name mapping) في *.module.css).
للتوافق مع CSP، عند تكوين nonce في وقت تشغيل webpack (__webpack_require__.nc)، فإن <style> المحقون بهذا الوضع يتلقى نفس nonce عبر السمة nonce (يعيد webpack استخدام nonce المقدم من التطبيق؛ ولا يقوم بإنشائه تلقائيًا).
module.exports = {
experiments: { css: true },
module: {
rules: [
{
test: /\.css$/,
type: "css/module",
parser: {
exportType: "style",
},
},
],
},
};Tree Shaking أفضل لتفكيك CommonJS
يمكن لـ Webpack الآن تحليل تعيينات التفكيك (destructuring assignments) بشكل ثابت مباشرة من require في CommonJS (و module.require) والتعامل مع الخصائص المفككة فقط كـ "صادرات مشار إليها"، بدلاً من افتراض بشكل متحفظ أن كائن exports بأكمله مستخدم. هذا يحسن إزالة الأكواد الميتة في عمليات البناء المحسنة ويمكن أن يقلل من حجم الحزمة في قواعد الأكواد التي لا تزال تستهلك وحدات CommonJS.
تأمل وحدة تصدر وظائف متعددة، ومستهلك يفصل إحداها فقط:
// math.js
exports.add = (a, b) => a + b;
exports.divide = (a, b) => a / b;
exports.multiply = (a, b) => a * b;
exports.subtract = (a, b) => a - b;// app.js
const { add } = require("./math");
console.log(add(2, 3));في الإصدارات السابقة، كان webpack يعامل require("./math") على أنه يشير إلى كائن الصادرات بأكمله. تم تضمين جميع الوظائف الأربع في الحزمة على الرغم من استخدام add فقط:
// الناتج المحزم (5.105 — مبسط)
const math = {
add: (a, b) => a + b,
subtract: (a, b) => a - b,
multiply: (a, b) => a * b,
divide: (a, b) => a / b,
};بدءًا من الإصدار 5.106، يتعرف webpack على نمط التفكيك ويضع علامة على add فقط كمشار إليها. يتم القضاء على الصادرات غير المستخدمة أثناء التحسين:
// الناتج المحزم (5.106 — مبسط)
const math_add = (a, b) => a + b;
// تم التخلص من subtract, multiply, divideيعمل هذا أيضًا مع module.require:
const { a, b } = module.require("./module");استيرادات مرحلة المصدر لـ WebAssembly (تجريبي)
يتضمن Webpack الآن دعمًا تجريبيًا لـ استيرادات مرحلة المصدر (Source Phase Imports) من TC39 عند استيراد وحدات WebAssembly.
المقترح حاليًا في المرحلة 3 ويقدم طريقة لاستيراد وحدة في مرحلة المصدر بدلاً من تقييمها على الفور. من الناحية العملية لـ WebAssembly، هذا يعني أنه يمكنك الحصول على WebAssembly.Module مُترجم أولاً، وإنشاء مثيل له لاحقًا مع استيراداتك الخاصة.
في الإصدار 5.106 من webpack، يركز هذا الدعم التجريبي على استيرادات مصدر WebAssembly ضمن experiments.sourceImport. في الإصدار الفرعي القادم، من المتوقع أن يتحول التركيز نحو دعم JavaScript.
قم بتمكين الميزة باستخدام experiments.sourceImport:
module.exports = {
experiments: {
asyncWebAssembly: true,
sourceImport: true,
},
};ثم استخدم إما صياغة مرحلة المصدر الثابتة أو الديناميكية:
// الشكل الثابت
import source wasmModule from "./module.wasm";
// الشكل الديناميكي
const wasmModule2 = await import.source("./module.wasm");
const instance = await WebAssembly.instantiate(wasmModule);يمكنك أيضًا رؤية مثال كامل في مستودع webpack: https://github.com/webpack/webpack/tree/main/examples/wasm-simple-source-phase
البدء مع create-webpack-app
أصبحت create-webpack-app الآن الطريقة الموصى بها لإعداد مشروع webpack جديد. في السابق، كانت هذه الوظيفة موجودة داخل webpack-cli كأمر webpack init، ولكن تم استخراجها في حزمتها المستقلة مع إصدار webpack-cli 7.
هذا يعني أنه يمكنك الآن إنشاء مشروع webpack جديد بأمر واحد، دون الحاجة إلى تثبيت webpack-cli أولاً:
npx create-webpack-appترشدك واجهة سطر الأوامر (CLI) خلال إعداد تفاعلي حيث تختار القطع التي تناسب مشروعك:
$ npx create-webpack-app
? Which of the following JS solutions do you want to use? Typescript
? Do you want to use webpack-dev-server? Yes
? Do you want to simplify the creation of HTML files for your bundle? Yes
? Do you want to add PWA support? No
? Which of the following CSS solutions do you want to use? CSS only
? Will you be using PostCSS in your project? Yes
? Do you want to extract CSS for every file? Only for Production
? Which package manager do you want to use? npm
[create-webpack] ℹ️ Initializing a new Webpack project...
[create-webpack] ✅ Project dependencies installed successfully!يتضمن المشروع المُولد webpack.config.js جاهز للعمل، وتكوين خادم التطوير، وإعداد المحمل/الإضافة للخيارات التي حددتها. من هناك، يمكنك البدء في التطوير على الفور:
cd my-project
npm startيتبع هذا النهج نفس النمط الذي نشرته أدوات مثل create-react-app و create-vite: أمر npx واحد ينقلك من الصفر إلى مشروع عامل بدون تكوين يدوي.
يمكنك أيضًا استخدام الأمر الفرعي init إذا كنت تفضل الشكل الصريح:
npx create-webpack-app initبالإضافة إلى إعداد المشروع، يمكن لـ create-webpack-app أيضًا إنشاء الكود الأساسي (boilerplate) لمحملات وإضافات مخصصة:
npx create-webpack-app loader
npx create-webpack-app pluginدعم السياق لـ VirtualUrlPlugin
تدعم إضافة VirtualUrlPlugin (عبر webpack.experiments.schemes.VirtualUrlPlugin) الآن خيار context الذي يحدد المجلد الأساسي المُستخدم لتحليل الاستيرادات النسبية داخل الوحدات الافتراضية. هذه الميزة حاليًا تجريبية، لأنها جزء من واجهة برمجة تطبيقات experiments.schemes.
هذا يجعل الوحدات الافتراضية تتصرف بشكل أشبه بالملفات الحقيقية: الكود مثل import "./utils" يُحلل بشكل متسق بدلاً من الرجوع إلى compiler.context وربما حله بشكل غير صحيح.
يمكن تعيين context لكل وحدة افتراضية (داخل تعريف الوحدة) أو كافتراضي على مستوى الإضافة. افتراضيًا يكون "auto"، والذي يحاول استنتاج السياق من معرف الوحدة الافتراضية أو المسار؛ وإلا فإنه يعود إلى compiler.context. من الناحية المفاهيمية، عندما تقوم بتعيين context لوحدة ما، فإن webpack يعامل تلك الوحدة الافتراضية كما لو أنها تعيش داخل ذلك المجلد لتحليل المسارات النسبية.
على سبيل المثال، إذا حددت معرف وحدة افتراضية virtual/table.js مع context: path.join(__dirname, "src/components")، فسيتم تحليل استيرادها الداخلي import "./utils" كما لو كان الملف هو src/components/table.js الذي يستورد src/components/utils.js.
const path = require("node:path");
const webpack = require("webpack");
module.exports = {
plugins: [
new webpack.experiments.schemes.VirtualUrlPlugin(
{
"src/components/button.js": {
context: "auto",
source() {
return "import { trim } from './utils'; export const button = trim('button ');";
},
},
"virtual/table.js": {
context: path.join(__dirname, "src/components"),
source() {
return "import { trim } from './utils'; export const table = trim('table ');";
},
},
},
{ context: "auto" },
),
],
};تحليل JavaScript تجريبي باستخدام oxc-parser
يتضمن Webpack الآن مثالًا يوضح كيفية استبدال محلل JavaScript الافتراضي بـ oxc-parser. يجب اعتبار هذا التكامل تجريبيًا بحتًا ولا يوصى به للاستخدام في الإنتاج.
بدلاً من ذلك، الغرض منه لـ بيئات التطوير أو فروع المقارنة المعيارية (benchmark)، مما يسمح للمجتمع بتجربة استراتيجيات تحليل بديلة في مشاريع حقيقية. يساعد هذا في تقييم التحسينات المحتملة في وقت التحليل وأداء البناء، بالإضافة إلى تحديد مشكلات التوافق المحتملة.
مثال
يقتصر التكوين التالي على تطبيق المحلل المخصص لملفات .js:
"use strict";
const oxcParse = require("./internals/oxc-parse");
/** @type {import("webpack").Configuration} */
module.exports = {
mode: "production",
entry: "./src/index.js",
module: {
rules: [
{
// تطبيق المحلل المخصص فقط لملفات JavaScript
test: /\.js$/,
parser: {
parse: oxcParse,
},
},
],
},
};يمكنك العثور على المثال الكامل في مستودع webpack: https://github.com/webpack/webpack/blob/main/examples/custom-javascript-parser/webpack.config.js
تحديثات النظام البيئي
- أصدرت Webpack-cli إصدارًا رئيسيًا جديدًا، 7.0.0. الحد الأدنى لإصدار Node.js المدعوم الآن هو
20.9.0، ويتم تحميل ملفات التكوين عبرimport()الديناميكي افتراضيًا، مما يُفعل الدعم الأصلي لتكوين TypeScript عبر تجريد أنواع Node.js (type stripping) دون الحاجة إلى محملات خارجية. تم استبدال وسيطة--node-envبـ--config-node-env، وتم إزالة واجهة برمجة التطبيقات البرمجية المهملة. بالإضافة إلى ذلك، أصبح الآن يُسمح بتجميد التكوين (configuration freezing)، وتم تحسين الإغلاق السلس (graceful shutdown) عند تفعيل ذاكرة التخزين المؤقت لنظام الملفات، وتم إجراء تحسينات عامة على الأداء. تحقق من الإصدار لمزيد من المعلومات. - أصدرت Webpack-dev-middleware إصدارًا رئيسيًا جديدًا، 8.0.0. الحد الأدنى لإصدار Node.js المدعوم الآن هو
20.9.0والحد الأدنى لإصدار webpack هو5.101.0. أصبحت وظيفةgetFilenameFromUrlالآن غير متزامنة، وتم تفعيل التخزين المؤقت الثابت للأصول (cacheImmutable) افتراضيًا، وهناك خيار جديدforwardErrorيسمح بتمرير الأخطاء إلى البرمجيات الوسيطة (middleware) التالية. كما تم إضافة دعم لاستخدام الإضافات، وتم إجراء تحسينات عامة على الأداء. تحقق من الإصدار لمزيد من المعلومات. - أصدرت إضافات مثل Compression-webpack-plugin, html-minimizer-webpack-plugin, css-minimizer-webpack-plugin, image-minimizer-webpack-plugin وغيرها من الإضافات إصدارات رئيسية جديدة لمواءمة الحد الأدنى لإصدار Node.js المدعوم إلى
20.9.0، مع الحفاظ على التناسق عبر النظام البيئي لـ webpack جنبًا إلى جنب مع الإصدارات الرئيسية الأخيرة من webpack-cli 7 و webpack-dev-middleware 8.
إصلاحات الأخطاء
تم حل العديد من الأخطاء منذ الإصدار 5.105. تحقق من سجل التغييرات (changelog) للحصول على كل التفاصيل.
شكر
شكر كبير لجميع المساهمين والرعاة الذين جعلوا Webpack 5.106 ممكنًا. دعمكم، سواء كان عبر المساهمة بالكود، أو التوثيق، أو الرعاية المالية، يساعد في استمرار تطور وتحسن Webpack للجميع.



