ModuleFederationPlugin
يسمح ModuleFederationPlugin لعملية build أن توفّر modules لتطبيقات مستقلة أخرى، أو تستهلك modules منها، وقت التشغيل.
import webpack from "webpack";
const { ModuleFederationPlugin } = webpack.container;
export default {
plugins: [
new ModuleFederationPlugin({
// أنواع الخيارات في TypeScript
runtime: string | false,
}),
],
};الخيارات
runtime
ينشئ runtime chunk جديدًا بالاسم الذي تحدده.
webpack.config.js
import webpack from "webpack";
const { ModuleFederationPlugin } = webpack.container;
export default {
plugins: [
new ModuleFederationPlugin({
runtime: "my-runtime-name",
}),
],
};مشاركة المكتبات
باستخدام المفتاح shared في الإعدادات، يمكنك تحديد المكتبات التي ستتم مشاركتها بين modules التابعة لـ Module Federation. اسم الحزمة هو نفسه الموجود في قسم dependencies داخل ملف package.json. لكن webpack، بشكل افتراضي، يشارك المستوى الجذري فقط من المكتبة.
import webpack from "webpack";
const { ModuleFederationPlugin } = webpack.container;
export default {
plugins: [
new ModuleFederationPlugin({
// يضيف date-fns كـ shared module
shared: ["date-fns"],
}),
],
};في تطبيقك، يمكن أن تكتب شيئًا مثل:
import { format } from "date-fns";
format(new Date(2014, 1, 11), "MM/dd/yyyy");وسيشارك webpack مكتبة date-fns تلقائيًا بين كل modules التابعة لـ Module Federation التي تعرّف date-fns كمكتبة مشتركة.
لكن إذا أردت الوصول إلى ملف ليس في جذر الحزمة، مثل date-fns/locale/en-GB/index.js، فأضف / إلى اسم الحزمة داخل إعداد shared:
import webpack from "webpack";
const { ModuleFederationPlugin } = webpack.container;
export default {
plugins: [
new ModuleFederationPlugin({
// يضيف date-fns كـ shared module
// ستتم مشاركة كل ملفات الحزمة
shared: ["date-fns/"],
}),
],
};صيغة / تسمح لك بالوصول إلى كل ملفات الحزمة. استخدمها فقط عند الحاجة، لأنها قد تؤثر في الأداء، خصوصًا في وضع development.
تحديد إصدارات الحزم
توجد ثلاث طرق لتحديد إصدارات المكتبات المشتركة.
صيغة Array
هذه الصيغة تسمح لك بمشاركة المكتبات باسم الحزمة فقط. هي مناسبة للتجارب السريعة، لكنها لا تكفي عادةً عند التوسع إلى بيئة production كبيرة، لأن مكتبات مثل react وreact-dom تحتاج شروطًا إضافية.
import webpack from "webpack";
const { ModuleFederationPlugin } = webpack.container;
export default {
plugins: [
new ModuleFederationPlugin({
// يضيف lodash كـ shared module
// يتم استنتاج الإصدار من package.json
// لا يوجد فحص للإصدار المطلوب
// لذلك سيستخدم دائمًا أعلى إصدار يجده
shared: ["lodash"],
}),
],
};صيغة Object
هذه الصيغة تعطيك تحكمًا أكبر في كل مكتبة مشتركة؛ تضع اسم الحزمة كمفتاح، وتضع الإصدار بصيغة semver كقيمة.
export default {
plugins: [
new ModuleFederationPlugin({
shared: {
// يضيف lodash كـ shared module
// يتم استنتاج الإصدار من package.json
// سيستخدم أعلى إصدار من lodash يطابق >= 4.17 و < 5
lodash: "^4.17.0",
},
}),
],
};صيغة Object مع تلميحات المشاركة
هذه الصيغة تسمح لك بإضافة تلميحات لكل حزمة مشتركة. تضع اسم الحزمة كمفتاح، وتكون القيمة object يحتوي على تلميحات تغيّر سلوك المشاركة.
import { readFileSync } from "node:fs";
const deps = JSON.parse(
readFileSync(new URL("./package.json", import.meta.url)),
).dependencies;
export default {
plugins: [
new ModuleFederationPlugin({
shared: {
// يضيف react كـ shared module
react: {
requiredVersion: deps.react,
singleton: true,
},
},
}),
],
};تلميحات المشاركة
eager
boolean
هذا التلميح يجعل webpack يضمّن module المقدّم وfallback مباشرة بدل جلب المكتبة بطلب غير متزامن. بمعنى آخر، يتيح استخدام هذا shared module داخل initial chunk. انتبه أيضًا إلى أن كل modules المقدّمة وfallback ستُحمّل دائمًا عند تفعيل هذا التلميح.
import
false | string
الـ module المقدّم الذي يجب وضعه في shared scope. يعمل هذا module أيضًا كـ fallback إذا لم يُعثر على shared module داخل shared scope، أو إذا كان الإصدار غير صالح. القيمة الافتراضية لهذا التلميح هي اسم الخاصية نفسها.
packageName
string
اسم الحزمة المستخدم لمعرفة الإصدار المطلوب من ملف الوصف. تحتاجه فقط عندما لا يمكن تحديد اسم الحزمة تلقائيًا من request.
requiredVersion
false string
يحدد هذا الحقل الإصدار المطلوب من الحزمة. يقبل semantic versioning مثل "^1.2.3". ويمكنه أيضًا استخراج الإصدار إذا كان موجودًا ضمن URL، مثل: "git+ssh://git@github.com:foo/bar.git#v1.0.0".
shareKey
string
يُبحث عن shared module المطلوب تحت هذا المفتاح داخل shared scope.
shareScope
string
اسم shared scope.
singleton
boolean
هذا التلميح يسمح بوجود إصدار واحد فقط من shared module داخل shared scope، وهو معطّل افتراضيًا. بعض المكتبات تستخدم حالة داخلية عامة، مثل react وreact-dom، لذلك من المهم أن تعمل نسخة واحدة فقط من المكتبة في الوقت نفسه.
إذا وجدت عدة إصدارات من الاعتماد نفسه داخل shared scope، فسيُستخدم أعلى إصدار semantic.
strictVersion
boolean
هذا التلميح يجعل webpack يرفض shared module إذا كان الإصدار غير صالح. القيمة الافتراضية تكون true عندما يكون local fallback module متاحًا والـ shared module ليس singleton، وإلا تكون false. ولا يكون له تأثير إذا لم تحدد إصدارًا مطلوبًا. إذا لم يُعثر على الإصدار المطلوب، فسيتم رمي runtime error.
version
false | string
إصدار module المقدّم. يسمح لـ webpack باستبدال الإصدارات المطابقة الأقل، لكن لا يستبدل الإصدارات الأعلى.
افتراضيًا، يستخدم webpack الإصدار الموجود في ملف package.json الخاص بالاعتماد.
أمثلة إضافية
export default {
plugins: [
new ModuleFederationPlugin({
// يضيف vue كـ shared module
// يتم استنتاج الإصدار من package.json
// سيستخدم دائمًا الإصدار المشترك، لكنه يطبع تحذيرًا إذا كان vue المشترك < 2.6.5 أو >= 3
shared: {
vue: {
requiredVersion: "^2.6.5",
singleton: true,
},
},
}),
],
};export default {
plugins: [
new ModuleFederationPlugin({
// يضيف vue كـ shared module
// لا يوجد إصدار محلي مقدّم
// سيصدر تحذيرًا إذا كان vue المشترك < 2.6.5 أو >= 3
shared: {
vue: {
import: false,
requiredVersion: "^2.6.5",
},
},
}),
],
};export default {
plugins: [
new ModuleFederationPlugin({
// يضيف vue كـ shared module
// لا يوجد إصدار محلي مقدّم
// سيرمي خطأ إذا كان vue المشترك < 2.6.5 أو >= 3
shared: {
vue: {
import: false,
requiredVersion: "^2.6.5",
strictVersion: true,
},
},
}),
],
};export default {
plugins: [
new ModuleFederationPlugin({
shared: {
"my-vue": {
// يمكن الإشارة إليه عبر import "my-vue"
import: "vue", // ستُستخدم حزمة "vue" كـ module مقدّم وfallback
shareKey: "shared-vue", // بهذا الاسم سيُوضع shared module داخل share scope
shareScope: "default", // سيُستخدم share scope بهذا الاسم
singleton: true, // يُسمح بإصدار واحد فقط من shared module
strictVersion: true, // لا تستخدم الإصدار المشترك إذا كان غير صالح. يرمي Singleton أو modules بدون fallback خطأ، وإلا يُستخدم fallback
version: "1.2.3", // إصدار shared module
requiredVersion: "^1.0.0", // الإصدار المطلوب من shared module
},
},
}),
],
};


