中文

通过 Webpack 5 中的 JavaScript 模块联邦释放微前端的力量。学习如何构建可扩展、可维护且独立的 Web 应用程序。

使用 Webpack 5 的 JavaScript 模块联邦:微前端综合指南

在不断发展的 Web 开发领域,构建大型复杂应用程序可能是一项艰巨的任务。传统的单体架构常常导致开发时间增加、部署瓶颈以及维护代码质量的挑战。微前端作为一种强大的架构模式应运而生,以应对这些挑战,它允许团队构建和部署更大型 Web 应用程序的独立部分。实现微前端最有前途的技术之一是 Webpack 5 中引入的JavaScript 模块联邦

什么是微前端?

微前端是一种架构风格,它将一个前端应用分解为更小的、独立的单元,这些单元可以由不同的团队自主开发、测试和部署。每个微前端负责一个特定的业务领域或功能,并在运行时组合在一起,形成完整的用户界面。

可以把它想象成一家公司:你不是拥有一个庞大的开发团队,而是有多个专注于特定领域的小团队。每个团队都可以独立工作,从而实现更快的开发周期和更轻松的维护。以亚马逊这样的大型电子商务平台为例,不同的团队可能分别管理产品目录、购物车、结账流程和用户账户管理。这些都可以是独立的微前端。

微前端的优势:

微前端的挑战:

什么是 JavaScript 模块联邦?

JavaScript 模块联邦是 Webpack 5 的一项功能,它允许您在运行时在单独编译的 JavaScript 应用程序之间共享代码。它使您能够将应用程序的部分内容作为“模块”暴露出来,供其他应用程序使用,而无需发布到像 npm 这样的中央仓库。

可以将模块联邦看作是创建应用程序联合生态系统的一种方式,其中每个应用程序都可以贡献自己的功能并使用其他应用程序的功能。这消除了构建时依赖的需要,并实现了真正独立的部署。

例如,一个设计系统团队可以将 UI 组件作为模块暴露出来,不同的应用团队可以直接从设计系统应用中使用这些组件,而无需将它们作为 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` 目录中,创建以下文件:

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` 目录中,创建以下文件:

  • `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`。您应该能看到主机应用程序,其中渲染了远程组件。

关键配置选项说明:

高级模块联邦技术

模块联邦提供了许多高级功能,可以帮助您构建更复杂的微前端架构。

动态远程

您可以在运行时动态加载远程应用程序的 URL,而不是在 Webpack 配置中硬编码。这使您可以轻松更新远程应用程序的位置,而无需重新构建主机应用程序。

例如,您可以将远程应用程序的 URL 存储在配置文件或数据库中,并使用 JavaScript 动态加载它们。

```javascript // 在 webpack.config.js 中 remotes: { remote: `promise new Promise(resolve => { const urlParams = new URLSearchParams(window.location.search); const remoteUrl = urlParams.get('remote'); // 假设 remoteUrl 是 'http://localhost:3001/remoteEntry.js' const script = document.createElement('script'); script.src = remoteUrl; script.onload = () => { // 模块联邦的关键在于远程应用 // 通过其在远程配置中的 name 来访问 resolve(window.remote); }; document.head.appendChild(script); })`, }, ```

现在您可以通过查询参数加载主机应用 `?remote=http://localhost:3001/remoteEntry.js`

带版本的共享模块

模块联邦可以自动处理共享模块的版本控制和去重,以确保只加载一个兼容版本的模块。这在处理具有许多依赖项的大型复杂应用程序时尤其重要。

您可以在 Webpack 配置中为每个共享模块指定版本范围。

```javascript // 在 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 中的 JavaScript 模块联邦提供了一种强大而灵活的方式来构建微前端架构。它允许您在运行时在单独编译的 JavaScript 应用程序之间共享代码,从而实现独立部署、技术多样性和更高的团队自主性。通过遵循本指南中概述的最佳实践,您可以利用模块联邦来构建可扩展、可维护和创新的 Web 应用程序。

前端开发的未来无疑正朝着模块化和分布式架构的方向发展。模块联邦为构建这些现代系统提供了关键工具,使团队能够以更快的速度、更高的灵活性和更强的弹性创建复杂的应用程序。随着技术的成熟,我们可以期待看到更多创新的用例和最佳实践的出现。