使用 micro-app 搭建微前端架构是一个非常务实的选择。与 qiankun 等基于路由劫持的框架不同,micro-app 的核心逻辑是基于 Web Components。
这意味着,你引入子应用的方式,就像在 HTML 中写一个 <div> 或 <iframe> 一样自然。这种“类原生”的隔离机制大大降低了上手门槛。
为了让你快速跑通流程,我们使用 React + Vite 来搭建一个最简模型:
-
主应用 (Host): 运行在
http://localhost:3000 -
子应用 (Child): 运行在
http://localhost:4000
第一步:初始化项目结构
首先,我们需要创建两个独立的 React 项目。在终端中执行以下操作:
Bash
# 创建主应用
npm create vite@latest main-app -- --template react-ts
# 创建子应用
npm create vite@latest child-app -- --template react-ts
安装依赖:
Bash
cd main-app && npm install
cd ../child-app && npm install
第二步:配置主应用 (Main App)
主应用的职责是加载 micro-app 的基座环境,并渲染子应用组件。
1. 安装依赖
在 main-app 目录下:
Bash
npm i @micro-zoe/micro-app --save
2. 初始化 MicroApp
在主应用的入口文件(通常是 src/main.tsx)中引入并启动。
TypeScript
// main-app/src/main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import microApp from '@micro-zoe/micro-app'
// 初始化 micro-app
microApp.start()
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
3. 引入子应用
在 src/App.tsx 中,我们使用 <micro-app> 标签来加载子应用。
注意:TypeScript 可能会报错提示无法识别
<micro-app>元素,这是因为它是自定义 Web Component。你可以暂时忽略,或者在src/vite-env.d.ts中添加声明(见文末“常见问题”)。
TypeScript
// main-app/src/App.tsx
import { useState } from 'react'
function App() {
return (
<div style={{ padding: 20 }}>
<h1>我是主应用 (Main App)</h1>
<hr />
{/* name: 子应用唯一名称
url: 子应用运行的地址
iframe: 开启iframe沙箱(可选,建议开启以获得更好隔离)
*/}
<micro-app
name="child-app"
url="http://localhost:4000/"
iframe
></micro-app>
</div>
)
}
export default App
4. 固定端口
修改 main-app/vite.config.ts,确保主应用跑在 3000 端口:
TypeScript
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
}
})
第三步:配置子应用 (Child App)
子应用本质上就是一个普通的 React 应用,但为了能被主应用加载,我们需要解决最核心的 跨域 (CORS) 问题。
因为主应用 (Port 3000) 请求子应用 (Port 4000) 的资源(HTML/JS/CSS)时,浏览器默认会拦截跨域请求。
1. 配置 CORS 和端口
修改 child-app/vite.config.ts:
TypeScript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
port: 4000, // 子应用端口
headers: {
// 允许跨域,这是微前端正常运行的关键
'Access-Control-Allow-Origin': '*',
}
}
})
2. 修改子应用内容
为了区分,修改 child-app/src/App.tsx 的 UI:
TypeScript
// child-app/src/App.tsx
function App() {
return (
<div style={{ background: '#f0f2f5', padding: 20, border: '1px dashed #1890ff' }}>
<h2>我是子应用 (Child App)</h2>
<p>我运行在: {window.location.href}</p>
</div>
)
}
export default App
第四步:运行与验证
-
打开一个终端,运行子应用:
Bash
cd child-app && npm run dev -
打开另一个终端,运行主应用:
Bash
cd main-app && npm run dev -
访问
http://localhost:3000。
预期结果: 你应该能看到主应用的标题下方,完整渲染出了子应用的灰色背景区域。
深入分析:可能遇到的问题
在实际开发中,你可能会遇到以下两个最常见的问题:
1. TypeScript 报错
因为 <micro-app> 不是标准的 HTML 标签,React 的 TS 类型定义中不包含它。
解决方法: 在主应用的 src/vite-env.d.ts 或新建 custom.d.ts 中添加:
TypeScript
declare namespace JSX {
interface IntrinsicElements {
'micro-app': any
}
}
2. 图片/资源加载 404
当子应用被主应用加载时,如果子应用里的图片使用的是相对路径(如 ./assets/logo.png),浏览器会基于主应用的域名(localhost:3000)去请求,导致 404。
解决方法:
-
Vite 场景:
micro-app的 iframe 模式通常能自动处理路径补全。 -
非 iframe 模式: 你需要在子应用中设置
publicPath。在child-app/src/main.tsx中:TypeScript
// 如果在微前端环境中,设置 public path if (window.__MICRO_APP_ENVIRONMENT__) { // 这一步通常构建工具配合,Vite 中较少直接操作 __webpack_public_path__ // 但 micro-app 会自动处理 link 和 script 标签的路径 }最稳健的做法: 在子应用中使用绝对路径引入图片,或者确保构建工具将资源处理为 Base64(如果是小图)。
总结
这个架构的逻辑闭环在于:主应用通过 Fetch 请求拉取子应用的 HTML,解析出其中的 CSS 和 JS 标签,然后在沙箱环境中执行这些 JS,最后将生成的 DOM 插入到 <micro-app> 标签内。
Web Component 仅仅是作为容器,真正的魔法在于 micro-app 对资源的加载和作用域的隔离。