MicroApp 快速上手

主应用 - react
1. 项目准备
1. 创建项目
- 创建主应用项目:npx create-react-app react18
- 创建子应用项目-react:npx create-react-app react18
- 创建子应用项目-vue3:vue create vue3
2. 安装相关依赖
- 【主应用】安装微前端框架: npm i @micro-zoe/micro-app --save
- 【主应用】安装路由依赖:npm i react-router-dom
- 【子应用-react】安装路由依赖:npm i react-router-dom
- 【子应用-react】安装跨域解决支持依赖:npm install react-app-rewired customize-cra --save-dev
- 【子应用-vue3】安装路由依赖:npm install vue-router
2. 搭建相关路由系统
- 
【主应用】路由系统 // router/index.js
 import { lazy, Suspense } from 'react'
 import { createBrowserRouter } from 'react-router-dom'
 import Home from '../pages/home'
 const React18 = lazy(() =>
 import(/* webpackChunkName: "react18" */ '../pages/React18')
 )
 const Vue3 = lazy(() => import(/* webpackChunkName: "vue3" */ '../pages/Vue3'))
 const router = createBrowserRouter([
 {
 path: '/',
 element: <Home />,
 errorElement: <div>404</div>,
 children: [
 {
 path: 'react18',
 element: (
 <Suspense fallback={<div>loading...</div>}>
 <React18 />
 </Suspense>
 ),
 },
 {
 path: 'vue3',
 element: (
 <Suspense fallback={<div>loading...</div>}>
 <Vue3 />
 </Suspense>
 ),
 },
 ],
 },
 ])
 export default router
- 
【主应用】路由系统相关组件 // react18
 const React18 = () => {
 return (
 <div>
 <micro-app
 name="react18"
 url="http://localhost:3311/"
 baseroute="/react18"
 />
 </div>
 )
 }
 export default React18
 // vue3
 const Vue3 = () => {
 return (
 <div>
 <micro-app name="vue3" url="http://localhost:3312/" baseroute="/vue3" />
 </div>
 )
 }
 export default Vue3
- 
【子应用-react】路由系统 // router/index.js
 import { createBrowserRouter } from 'react-router-dom'
 import { lazy, Suspense } from 'react'
 import Home from '../pages/home'
 const About = lazy(() =>
 import(/* webpackChunkName: "about" */ '../pages/about')
 )
 const Detail = lazy(() =>
 import(/* webpackChunkName: "detail" */ '../pages/detail')
 )
 const router = createBrowserRouter(
 [
 {
 path: '/',
 element: <Home />,
 // 这里放置自己的路由即可
 children: [
 {
 path: '/about',
 element: (
 <Suspense fallback={<div>loading</div>}>
 <About />
 </Suspense>
 ),
 },
 {
 path: 'detail/:id',
 element: (
 <Suspense fallback={<div>loading</div>}>
 <Detail />
 </Suspense>
 ),
 },
 ],
 },
 ],
 // 注意此处为微前端侵入性修改
 {
 basename: window.__MICRO_APP_BASE_ROUTE__ || '/',
 }
 )
 export default router
- 
【子应用-vue3】路由系统 import { createRouter, createWebHistory } from 'vue-router'
 const router = createRouter({
 // 注意此处为微前端侵入性修改
 history: createWebHistory(
 window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL
 ),
 routes: [
 {
 path: '/detail',
 name: 'detail',
 component: () => import('../pages/Detail.vue'),
 },
 {
 path: '/about',
 name: 'about',
 component: () => import('../pages/AboutView.vue'),
 },
 ],
 })
 export default router
3. 引入微前端框架
- 
【主应用】入口文件引入框架 // index.js
 import microApp from '@micro-zoe/micro-app'
 microApp.start()
4. 子应用跨域问题处理
- 
【子应用-react】修改package.json "scripts": {
 "start": "react-app-rewired start",
 "build": "react-app-rewired build",
 "test": "react-app-rewired test",
 "eject": "react-scripts eject"
 },
- 
【子应用-react】根目录下添加 config-overrides.jsconst { overrideDevServer } = require('customize-cra')
 module.exports = {
 devServer: overrideDevServer((config) => {
 return {
 ...config,
 headers: {
 'Access-Control-Allow-Origin': '*',
 },
 }
 }),
 }
- 
【子应用-vue】根目录 vue.config.js中添加配置const { defineConfig } = require('@vue/cli-service')
 module.exports = defineConfig({
 // ...
 devServer: {
 port: 3312,
 headers: {
 'Access-Control-Allow-Origin': '*',
 },
 },
 })
5. 子应用设置publicPath
- 
【子应用-react】src目录下创建名称为 public-path.js的文件,并添加如下内容// __MICRO_APP_ENVIRONMENT__和__MICRO_APP_PUBLIC_PATH__是由micro-app注入的全局变量
 if (window.__MICRO_APP_ENVIRONMENT__) {
 // eslint-disable-next-line
 __webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__
 }
- 
【子应用-react】入口文件的 最顶部引入public-path.js// entry
 import './public-path'
- 
【子应用-vue】src目录下创建名称为 public-path.js的文件,并添加 同上述react子应用中相同内容
- 
【子应用-vue】入口文件的 最顶部引入public-path.js
🏷提示:
到这里已经完成一个微前端的基本搭建工作,展示效果如下:

整个接入过程非常简单,侵入性的操作总结有:
- 主应用
- microApp.start()
- 添加微应用的容器组件
- 添加路由指向这个容器组件
 
- 微应用
- 修改 public-path
- 添加跨域访问
- 自动切换路由的 basename
 
6. 数据通信
父传子
- 
【主应用】修改路由 // router/index.js
 import { lazy, Suspense } from 'react'
 import { createBrowserRouter } from 'react-router-dom'
 import Home from '../pages/home'
 const React18 = lazy(() =>
 import(/* webpackChunkName: "react18" */ '../pages/React18')
 )
 const Vue3 = lazy(() => import(/* webpackChunkName: "vue3" */ '../pages/Vue3'))
 const router = createBrowserRouter([
 {
 path: '/*',
 element: <Home />,
 errorElement: <div>404</div>,
 children: [
 {
 path: 'react18/*',
 element: (
 <Suspense fallback={<div>loading</div>}>
 <React18 />
 </Suspense>
 ),
 },
 {
 path: 'vue3/*',
 element: (
 <Suspense fallback={<div>loading</div>}>
 <Vue3 />
 </Suspense>
 ),
 },
 ],
 },
 ])
 export default router
- 
【主应用】页面组件添加以下内容 // React18
 const location = useLocation()
 useEffect(() => {
 // 第一个参数为子应用名称
 microApp.setData('react18', {
 path: location.pathname.replace('/react18', ''),
 })
 }, [location.pathname])
 // 其他页面组件将相应第一个参数和路由进行修改即可
- 
【子应用-react】在首页添加监听事件并重定向路由 const navigate = useNavigate()
 useEffect(() => {
 function dataListener(data) {
 if (data.path) {
 navigate(data.path)
 }
 }
 if (window.__MICRO_APP_ENVIRONMENT__) {
 window.microApp.addDataListener(dataListener)
 }
 return () => {
 if (window.__MICRO_APP_ENVIRONMENT__) {
 // 解绑监听函数
 window.microApp.removeDataListener(dataListener)
 // 清空当前子应用的所有绑定函数(全局数据函数除外)
 window.microApp.clearDataListener()
 }
 }
 }, [])
- 
【子应用-vue】在首页添加监听事件并重定向路由 mounted() {
 const router = useRouter()
 function dataListener(data) {
 if (data.path) {
 router.push(data.path)
 }
 }
 if (window.__MICRO_APP_ENVIRONMENT__) {
 window.microApp.addDataListener(dataListener)
 }
 },
 unmounted() {
 if (window.__MICRO_APP_ENVIRONMENT__) {
 // 解绑监听函数
 window.microApp.removeDataListener()
 // 清空当前子应用的所有绑定函数(全局数据函数除外)
 window.microApp.clearDataListener()
 }
 },
子 传父
- 
【子应用-react】监听路由改变 // home/index.js
 const location = useLocation()
 useEffect(() => {
 if (window.microApp) {
 window.microApp.dispatch({
 path: location.pathname,
 })
 }
 }, [location.pathname])
- 
【主应用】获取数据并做出响应 // home/index.js
 const [selectedKeys, setSelectedKeys] = useState([])
 useEffect(() => {
 function dataListener(data) {
 setSelectedKeys([`/react18${data.path}`])
 }
 microApp.addDataListener('react18', dataListener)
 return () => {
 // 解绑监听my-app子应用的函数
 microApp.removeDataListener('react18', dataListener)
 // 清空所有监听appName子应用的函数
 microApp.clearDataListener('react18')
 }
 }, [])子应用发送数据等操作同理,这里就不做演示了,可直接看源码~ 
完成效果如下:
