微前端架构在大型项目中的落地经验

一个会部署的人
2025-06-27 10:44
阅读 631

开篇:什么是微前端?它有什么用?

开篇:什么是微前端?它有什么用?

想象一下,你和几个朋友一起盖一栋房子。大家分别负责厨房、客厅、卧室等不同的部分。每个人按照统一的设计风格来建造自己的房间,最后再拼装在一起,形成一个完整的家。

微前端(Micro Frontends) 就是类似的思想,只不过这个“房子”是一个网站或应用程序,而“房间”是它的各个功能模块。

通俗理解: 微前端是一种将大型前端应用拆分成多个小型独立应用的技术方案,每个小应用可以由不同团队开发、部署和维护,并最终集成在一个主页面中运行。

主要作用有:

  • 提高项目可维护性
  • 支持多技术栈共存
  • 团队分工更清晰
  • 部署更加灵活

环境准备:一步步搭建我们的开发环境

环境准备:一步步搭建我们的开发环境

为了方便演示,我们使用两个基于React的子项目(也支持其他框架),并通过Webpack实现模块联邦(Module Federation)来实现微前端效果。

1. 安装Node.js与npm

确保你的电脑上已安装 Node.js 和 npm:

node -v && npm -v

如果没有,请前往 https://nodejs.org 下载并安装 LTS 版本。

2. 创建主应用容器

创建主项目文件夹:

mkdir microfrontend-main
cd microfrontend-main
npm init -y

安装 React 和 Webpack 相关依赖:

npm install react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin

新建 src/index.js 主入口文件:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';

const App = () => <div>这是主应用</div>;

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

创建 HTML 模板文件 public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>微前端主应用</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>

配置 Webpack:创建 webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  entry: './src/index.js',
  mode: 'development',
  devServer: {
    port: 3000,
    open: true,
    historyApiFallback: true
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].bundle.js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './public/index.html'
    })
  ]
};

运行一下看看是否成功:

npx webpack serve

如果你看到 “这是主应用”,说明环境搭建成功!


核心概念:微前端的关键要素

✅ 微前端的三大核心组成部分

角色 职责
主应用 负责整合所有子应用,提供布局壳
子应用 各个独立的业务功能模块
加载机制 负责按需动态加载子应用

🔧 技术关键词解释

术语 解释
模块联邦 Webpack 的一个特性,让多个构建结果共享模块资源
生命周期钩子 子应用暴露的挂载、卸载方法,用于被主应用控制
通信机制 不同子应用之间传递消息的方法,比如全局状态管理或事件总线

实战项目:手把手带你做一个微前端项目

我们现在来实现一个简单的电商系统,其中包含两个子应用:

  • 商品列表(商品子应用)
  • 用户中心(用户子应用)

步骤1️⃣ 创建子应用:商品模块

创建子项目目录

mkdir product-app
cd product-app
npm init -y

安装依赖:

npm install react react-dom
npm install --save-dev webpack webpack-cli webpack-dev-server html-webpack-plugin @module-federation/webpack

编写组件:

// product-app/src/ProductList.jsx
import React from 'react';

export const ProductList = () => (
  <div style={{ border: "1px solid blue", margin: "10px" }}>
    <h2>商品列表</h2>
    <ul>
      <li>衣服</li>
      <li>手机</li>
      <li>鞋子</li>
    </ul>
  </div>
);

移动端适配方案-1

修改入口文件:

// product-app/src/index.js
import { ProductList } from './ProductList';

window.renderProductList = (containerId) => {
  const root = document.getElementById(containerId);
  const rootElement = document.createElement('div');
  root.appendChild(rootElement);

  const ReactDOM = require('react-dom/client');
  ReactDOM.createRoot(rootElement).render(<ProductList />);
};

if (!window.__MICRO_APP_ENV__) {
  window.renderProductList('root');
}

配置 Webpack 文件:

// product-app/webpack.config.js
const ModuleFederationPlugin = require('@module-federation/webpack').ModuleFederationPlugin;
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');


![移动端适配方案-2](https://code-guide.oss.shanghai.autogptai.club/common/file/download?name=date2025062710/7e012704-0936-4ba7-8c49-080b523d4ba0.jpg)


module.exports = {
  entry: './src/index.js',
  mode: 'development',
  devServer: {
    port: 3001,
    open: true,
    headers: {
      'Access-Control-Allow-Origin': '*'
    }
  },
  output: {
    publicPath: 'auto',
  },
  module: {
    rules: [{ test: /jsx?$/, loader: 'babel-loader', exclude: /node_modules/ }],
  },
  resolve: {
    extensions: ['.js', '.jsx'],
  },
  plugins: [
    new ModuleFederationPlugin({
      name: 'product_app',
      filename: 'remoteEntry.js',
      remotes: {},
      exposes: {
        './ProductList': './src/ProductList',
      },
      shared: {
        react: { singleton: true, requiredVersion: '^17.0.0' },
        'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
      },
    }),
    new HtmlWebpackPlugin({
      template: '../microfrontend-main/public/index.html',
    }),
  ],
};

现在启动服务:

cd product-app
npx webpack serve

访问 http://localhost:3001 应该能看到商品列表。


步骤2️⃣ 在主应用中加载子应用

我们需要让主应用知道远程子应用的地址,并加载其组件。

修改 webpack.config.js

const ModuleFederationPlugin = require('@module-federation/webpack').ModuleFederationPlugin;

plugins: [
  new ModuleFederationPlugin({
    name: 'main_app',
    remotes: {
      product_app: 'product_app@http://localhost:3001/remoteEntry.js',
    },
    shared: {
      react: { singleton: true, requiredVersion: '^17.0.0' },
      'react-dom': { singleton: true, requiredVersion: '^17.0.0' },
    },
  }),

  // 其他插件...
]

然后,在主应用页面中加载商品模块:

// src/index.js
import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom/client';

const App = () => {
  const containerRef = useRef(null);

  useEffect(() => {
    import('product_app/ProductList').then(({ ProductList }) => {
      ReactDOM.createRoot(containerRef.current).render(<ProductList />);
    });
  }, []);

  return (
    <div>
      <h1>电商平台主页</h1>
      <div ref={containerRef}></div>
    </div>
  );
};

ReactDOM.createRoot(document.getElementById('root')).render(<App />);

重新运行主应用:

cd microfrontend-main
npx webpack serve

如果一切顺利,你应该看到商品组件被成功嵌入到主页里了!


常见问题:新手最容易踩坑的地方

❓Q1:子应用无法加载,报错“Cannot find module”

原因及解决办法:

  • 确保子应用的 Webpack 配置设置了 publicPath: 'auto'
  • 确保主应用通过 import('xxx') 加载子模块

❓Q2:两个子应用样式冲突怎么办?

建议做法:

  • 使用 CSS Modules 或 BEM 命名规范
  • 将样式包裹在子应用的容器内(如 iframe 包裹)
  • 使用 Shadow DOM 隔离样式(进阶)

❓Q3:如何在子应用间通信?

✅ 推荐方式:

  • 使用全局事件总线 window.dispatchEvent(new CustomEvent(...))
  • 引入 Redux + localStorage 等共享状态机制
  • 使用 URL 参数进行跳转传参

学习建议:下一步往哪走?

微前端是个非常实用但略复杂的技术方向,掌握基础后你可以继续学习以下内容:

阶段 学习建议
🔹 初级 继续练习不同框架混合使用、路由同步
🔹 中级 学习子应用生命周期管理、性能优化
🔹 高级 研究 qiankun 框架、iframe 隔离、CSS-in-JS
🔹 架构师方向 学习部署策略、CDN 缓存、权限隔离

推荐开源工具:


结语

恭喜你完成了这篇《微前端架构在大型项目中的落地经验》教程!希望你现在对“微前端”有了更直观的认识,并且能够动手实践一个最简版的微前端项目。

记住一句话:技术是用来解决问题的,不是制造麻烦的。

保持好奇,持续实践,你会越来越强大!


📝 作者提示:如果你想获得完整代码示例或想深入学习微前端高级技巧,请留言或关注我获取更多资料。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝