العربية

أطلق العنان لقوة الواجهات الأمامية المصغرة مع اتحاد وحدات جافاسكريبت في Webpack 5. تعلم كيفية بناء تطبيقات ويب قابلة للتطوير والصيانة ومستقلة.

اتحاد وحدات جافاسكريبت (Module Federation) مع Webpack 5: دليل شامل للواجهات الأمامية المصغرة

في المشهد المتطور باستمرار لتطوير الويب، يمكن أن يكون بناء التطبيقات الكبيرة والمعقدة مهمة شاقة. غالبًا ما تؤدي البنى المترابطة التقليدية إلى زيادة وقت التطوير، واختناقات النشر، وتحديات في الحفاظ على جودة الكود. ظهرت الواجهات الأمامية المصغرة (Micro-frontends) كنمط معماري قوي لمواجهة هذه التحديات، مما يسمح للفرق ببناء ونشر أجزاء مستقلة من تطبيق ويب أكبر. واحدة من أكثر التقنيات الواعدة لتنفيذ الواجهات الأمامية المصغرة هي اتحاد وحدات جافاسكريبت (JavaScript Module Federation)، التي تم تقديمها في Webpack 5.

ما هي الواجهات الأمامية المصغرة؟

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

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

فوائد الواجهات الأمامية المصغرة:

تحديات الواجهات الأمامية المصغرة:

ما هو اتحاد وحدات جافاسكريبت (JavaScript Module Federation)؟

اتحاد وحدات جافاسكريبت هو ميزة في Webpack 5 تسمح لك بمشاركة الكود بين تطبيقات جافاسكريبت المترجمة بشكل منفصل في وقت التشغيل. يمكّنك من عرض أجزاء من تطبيقك كـ "وحدات" يمكن استهلاكها من قبل تطبيقات أخرى، دون الحاجة إلى نشرها في مستودع مركزي مثل npm.

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

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

المفاهيم الأساسية في اتحاد الوحدات:

إعداد اتحاد الوحدات مع Webpack 5: دليل عملي

دعنا نمر بمثال عملي لإعداد اتحاد الوحدات مع Webpack 5. سننشئ تطبيقين بسيطين: تطبيق مستضيف (Host) وتطبيق بعيد (Remote). سيعرض التطبيق البعيد مكونًا، وسيستهلكه التطبيق المستضيف.

1. إعداد المشروع

أنشئ مجلدين منفصلين لتطبيقاتك: `host` و `remote`.

```bash mkdir host remote cd host npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom cd ../remote npm init -y npm install webpack webpack-cli webpack-dev-server html-webpack-plugin --save-dev npm install react react-dom ```

2. إعداد التطبيق البعيد (Remote)

في مجلد `remote`، أنشئ الملفات التالية:

src/index.js:

```javascript import React from 'react'; import ReactDOM from 'react-dom/client'; import RemoteComponent from './RemoteComponent'; const App = () => (

Remote Application

); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

src/RemoteComponent.jsx:

```javascript import React from 'react'; const RemoteComponent = () => (

This is a Remote Component!

Rendered from the Remote Application.

); export default RemoteComponent; ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3001, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'remote', filename: 'remoteEntry.js', exposes: { './RemoteComponent': './src/RemoteComponent', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

أنشئ `public/index.html` ببنية HTML أساسية. المهم هو وجود `

`

3. إعداد التطبيق المستضيف (Host)

في مجلد `host`، أنشئ الملفات التالية:

  • `src/index.js`: نقطة الدخول للتطبيق.
  • `webpack.config.js`: ملف إعدادات Webpack.

src/index.js:

```javascript import React, { Suspense } from 'react'; import ReactDOM from 'react-dom/client'; const RemoteComponent = React.lazy(() => import('remote/RemoteComponent')); const App = () => (

Host Application

Loading Remote Component...
}>
); const root = ReactDOM.createRoot(document.getElementById('root')); root.render(); ```

webpack.config.js:

```javascript const HtmlWebpackPlugin = require('html-webpack-plugin'); const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin'); const path = require('path'); module.exports = { entry: './src/index', mode: 'development', devServer: { port: 3000, static: { directory: path.join(__dirname, 'dist'), }, }, output: { publicPath: 'auto', }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-react', '@babel/preset-env'], }, }, }, ], }, plugins: [ new ModuleFederationPlugin({ name: 'host', remotes: { remote: 'remote@http://localhost:3001/remoteEntry.js', }, shared: { react: { singleton: true, eager: true }, 'react-dom': { singleton: true, eager: true }, }, }), new HtmlWebpackPlugin({ template: './public/index.html', }), ], resolve: { extensions: ['.js', '.jsx'], }, }; ```

أنشئ `public/index.html` ببنية HTML أساسية (مشابهة للتطبيق البعيد). المهم هو وجود `

`

4. تثبيت Babel

في كلا المجلدين `host` و `remote`، قم بتثبيت اعتماديات Babel:

```bash npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader ```

5. تشغيل التطبيقات

في كلا المجلدين `host` و `remote`، أضف السكربت التالي إلى `package.json`:

```json "scripts": { "start": "webpack serve" } ```

الآن، ابدأ كلا التطبيقين:

```bash cd remote npm start cd ../host npm start ```

افتح متصفحك وانتقل إلى `http://localhost:3000`. يجب أن ترى التطبيق المستضيف مع المكون البعيد معروضًا بداخله.

شرح خيارات الإعداد الرئيسية:

تقنيات متقدمة في اتحاد الوحدات

يقدم اتحاد الوحدات العديد من الميزات المتقدمة التي يمكن أن تساعدك في بناء معماريات واجهات أمامية مصغرة أكثر تطورًا.

الجهات البعيدة الديناميكية (Dynamic Remotes)

بدلاً من كتابة عناوين URL للتطبيقات البعيدة بشكل ثابت في إعدادات Webpack، يمكنك تحميلها ديناميكيًا في وقت التشغيل. يتيح لك هذا تحديث موقع التطبيقات البعيدة بسهولة دون الحاجة إلى إعادة بناء التطبيق المستضيف.

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

```javascript // In webpack.config.js remotes: { remote: `promise new Promise(resolve => { const urlParams = new URLSearchParams(window.location.search); const remoteUrl = urlParams.get('remote'); // Assume remoteUrl is something like 'http://localhost:3001/remoteEntry.js' const script = document.createElement('script'); script.src = remoteUrl; script.onload = () => { // the key of module federation is that the remote app is // available using the name in the remote resolve(window.remote); }; document.head.appendChild(script); })`, }, ```

الآن يمكنك تحميل التطبيق المستضيف مع معامل استعلام `?remote=http://localhost:3001/remoteEntry.js`

إدارة إصدارات الوحدات المشتركة

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

يمكنك تحديد نطاق الإصدار لكل وحدة مشتركة في إعدادات Webpack.

```javascript // In webpack.config.js shared: { react: { singleton: true, eager: true, requiredVersion: '^18.0.0' }, 'react-dom': { singleton: true, eager: true, requiredVersion: '^18.0.0' }, }, ```

محملات الوحدات المخصصة

يسمح لك اتحاد الوحدات بتعريف محملات وحدات مخصصة يمكن استخدامها لتحميل الوحدات من مصادر مختلفة أو بتنسيقات مختلفة. يمكن أن يكون هذا مفيدًا لتحميل الوحدات من شبكة توصيل المحتوى (CDN) أو من سجل وحدات مخصص.

مشاركة الحالة بين الواجهات الأمامية المصغرة

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

أفضل الممارسات لتنفيذ الواجهات الأمامية المصغرة مع اتحاد الوحدات

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

أمثلة واقعية لاتحاد الوحدات قيد التنفيذ

في حين أن دراسات الحالة المحددة غالبًا ما تكون سرية، فإليك بعض السيناريوهات العامة حيث يمكن أن يكون اتحاد الوحدات مفيدًا بشكل لا يصدق:

الخلاصة

يوفر اتحاد وحدات جافاسكريبت في Webpack 5 طريقة قوية ومرنة لبناء معماريات الواجهات الأمامية المصغرة. يسمح لك بمشاركة الكود بين تطبيقات جافاسكريبت المترجمة بشكل منفصل في وقت التشغيل، مما يتيح عمليات نشر مستقلة وتنوعًا تقنيًا وتحسين استقلالية الفريق. باتباع أفضل الممارسات الموضحة في هذا الدليل، يمكنك الاستفادة من اتحاد الوحدات لبناء تطبيقات ويب قابلة للتطوير والصيانة ومبتكرة.

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