体验微前端
通过本章你可以了解到:
- 如何创建微前端项目的主应用、子应用。
- 微前端项目开发的基本流程。
创建应用
目前项目的路由模式分为以下三种
- 约定式路由 (设置
router: true
并使用文件路由)
- 自控式路由 (设置
router: true
并自己创建 BrowserRouter
等)
- 其他 (设置
router: false
项目内自己安装和使用 react-router-dom
)
在本教程中我们会为主应用创建两个子应用 Table 和 Dashboard (Table 为约定式路由,Dashboard 为自控式路由)
创建约定式路由主应用
通过命令行工具初始化项目:
mkdir masterApp && cd masterApp
npx @modern-js/create@latest
? 请选择你想创建的工程类型:Web 应用
? 请选择开发语言:TS
? 请选择包管理工具:pnpm
完成项目创建后我们可以通过 pnpm run new
来开启 微前端
功能:
? 请选择你想要的操作 启用可选功能
? 请选择功能名称 启用「微前端」模式
接下来,让我们注册微前端插件并添加开启微前端主应用,并增加子应用列表:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';
export default defineConfig({
runtime: {
router: true,
masterApp: {
apps: [{
name: 'Table',
entry: 'http://localhost:8081',
// activeWhen: '/table'
}, {
name: 'Dashboard',
entry: 'http://localhost:8082'
// activeWhen: '/dashboard'
}]
},
},
plugins: [appTools(), garfishPlugin()],
});
然后我们在 routes 文件夹下新建两个目录
- table (用于加载约定式路由子应用)
- dashboard (用于加载自控式路由子应用)
在这两个目录下我们需要新建一个 $.tsx
文件作为主应用约定式路由的入口($ 代表模糊匹配,即 /table
和 /table/test
都会匹配到这个 $.tsx
作为该路由的入口文件,这会保证在微前端场景下正确加载子应用路由)
加载约定式路由子应用
src/routes/table/$.tsx
import { useModuleApps } from '@modern-js/plugin-garfish/runtime';
const Index = () => {
const { Table } = useModuleApps();
return (
<div>
<Table />
</div>
);
};
export default Index;
加载自控式路由子应用
src/routes/dashboard/$.tsx
import { useModuleApps } from '@modern-js/plugin-garfish/runtime';
const Index = () => {
const { Dashboard } = useModuleApps();
return (
<div>
<Dashboard />
</div>
);
};
export default Index;
路由跳转
此时主应用配置已经完成,通过路由即可加载子应用,修改主应用的 layout.tsx
来跳转路由
src/route/layout.tsx
import { Outlet, Link } from '@modern-js/runtime/router';
const Layout = () => (
<div>
<div>
<Link to={'/table'}>加载约定式路由子应用</Link>
</div>
<div>
<Link to={'/dashboard'}>加载自控式路由子应用</Link>
</div>
<div>
<Link to={'/'}>卸载子应用</Link>
</div>
<Outlet />
</div>
);
export default Layout;
创建自控式路由主应用
通过命令行工具初始化项目:
mkdir masterApp && cd masterApp
npx @modern-js/create@latest
? 请选择你想创建的工程类型:Web 应用
? 请选择开发语言:TS
? 请选择包管理工具:pnpm
完成项目创建后我们可以通过 pnpm run new
来开启 微前端
功能:
? 请选择你想要的操作 启用可选功能
? 请选择功能名称 启用「微前端」模式
接下来,让我们注册微前端插件并添加开启微前端主应用,并增加子应用列表:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';
export default defineConfig({
runtime: {
router: true,
masterApp: {
apps: [{
name: 'Table',
entry: 'http://localhost:8081',
// activeWhen: '/table'
}, {
name: 'Dashboard',
entry: 'http://localhost:8082'
// activeWhen: '/dashboard'
}]
},
},
plugins: [appTools(), garfishPlugin()],
});
由于是自控式路由,我们删除掉 routes
文件夹并在 src
目录下增加 App.tsx
文件,此处如果使用的 非 MApp
组件,需要通过 React Router v6
的 createBrowserRouter
API 来创建路由
加载子应用
src/App.tsx
import { useModuleApps } from '@modern-js/plugin-garfish/runtime';
import { RouterProvider, Route, createBrowserRouter, createRoutesFromElements, BrowserRouter, Link, Outlet } from '@modern-js/runtime/router';
const AppLayout = () => (
<>
<div><Link to={'/table'}>加载约定式路由子应用</Link></div>
<div><Link to={'/dashboard'}>加载自控式路由子应用</Link></div>
<div><Link to={'/'}>卸载子应用</Link></div>
<Outlet />
</>
)
export default () => {
const { apps, MApp, Table, Dashboard } = useModuleApps();
// 使用的不是 MApp 组件,需要使用 createBrowserRouter 来创建路由
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<AppLayout />}>
<Route key={'table'} path={'table/*'} element={<Table />} />
<Route key={'dashboard'} path={'dashboard/*'} element={<Dashboard />} />
</Route>
)
);
return (
// 方法一:使用 MApp 自动根据配置的 activeWhen 参数加载子应用(本项目配置在 modern.config.ts 中)
// <BrowserRouter>
// <MApp />
// </BrowserRouter>
// 方法二:手动写 Route 组件方式加载子应用,方便于需要鉴权等需要前置操作的场景
<>
<RouterProvider router={router} />
</>
);
};
创建其他主应用
项目内自己安装和使用 react-router-dom
, 与自控式路由唯一的区别是, 设置 router: false
后 plugin-garfish 无法获得 useLocation
useHref
等 hook 来辅助计算 basename 和主子应用路由同步
import { useLocation, useHref } from 'react-router-dom';
const App = () => {
const basename = useHref('/table');
const { Table } = useModuleApps();
return <Table useLocation={useLocation} basename={basename} />;
};
创建约定式路由子应用
通过命令行工具初始化项目:
mkdir table && cd table
npx @modern-js/create@latest
按照如下选择,生成项目:
? 请选择你想创建的工程类型:Web 应用
? 请选择开发语言:TS
? 请选择包管理工具:pnpm
我们执行 pnpm run new
来开启 微前端
功能:
? 请选择你想要的操作 启用可选功能
? 请选择功能名称 启用「微前端」模式
接下来,让我们注册微前端插件并修改 modern.config.ts
,添加微前端子应用的配置 deploy.microFrontend
:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';
export default defineConfig({
dev: {
port: 8081,
},
runtime: {
router: true,
state: true,
},
deploy: {
microFrontend: true,
},
plugins: [appTools(), garfishPlugin()],
});
添加 src/routes/page.tsx
代码
src/routes/page.tsx
const Index = () => {
return (
<div className="container-box">subApp: 约定式路由的子应用的根路由</div>
);
};
export default Index;
创建自控式路由子应用
通过命令行工具初始化项目:
mkdir dashboard && cd dashboard
npx @modern-js/create@latest
按照如下选择,生成项目:
? 请选择你想创建的工程类型:Web 应用
? 请选择开发语言:TS
? 请选择包管理工具:pnpm
我们执行 pnpm run new
来开启 微前端
:
? 请选择你想要的操作 启用可选功能
? 请选择功能名称 启用「微前端」模式
接下来,让我们注册微前端插件并修改 modern.config.ts
,添加微前端子应用的配置 deploy.microFrontend
:
modern.config.ts
import { appTools, defineConfig } from '@modern-js/app-tools';
import { garfishPlugin } from '@modern-js/plugin-garfish';
export default defineConfig({
dev: {
port: 8082,
},
runtime: {
router: true,
state: true,
},
deploy: {
microFrontend: true,
},
plugins: [appTools(), garfishPlugin()],
});
自控式路由需要删除掉 routes
文件夹并在 src
目录下新建 App.tsx
并在 src/App.tsx
添加代码,注意需要从 props
中解析并传递 basename
给 BrowserRouter
src/App.tsx
import { BrowserRouter, Route, Routes } from '@modern-js/runtime/router';
export default (props: { basename: string }) => {
const { basename } = props;
return (
<BrowserRouter basename={basename}>
<Routes>
<Route index element={<div>自控式路由子应用根路由</div>} />
<Route path={'path'} element={<div>自控式路由子应用子路由</div>} />
</Routes>
</BrowserRouter>
);
};
调试
按顺序在目录执行 pnpm run dev
命令启动应用:
- masterApp 主应用
http://localhost:8080
- table 子应用(约定式路由)
http://localhost:8081
- dashboard 子应用(自控式路由)
http://localhost:8082
访问主应用地址 http://localhost:8080
在完成了微前端整体开发流程的体验后,你可以进一步了解如何 开发主应用
Modern.js 微前端和直接使用 Garfish 的区别
使用纯 Garfish
API 开发微前端应用时
- 主应用:
- 安装 Garfish 依赖并使用
Garfish.run
注册子应用 参考
- 提供一个常驻的
DOM
节点供子应用挂载 参考
- 子应用:
- 导出
provider
参考
- 设置应用的
basename
参考
区别于直接使用 Garfish
运行时 API 开发微前端项目,Modern.js
的微前端方案更加开箱即用。
使用 pnpm new
启用微前端模式后会自动在 Modern.js
应用中集成 Garfish
插件,在 Garfish
插件的加持下,你只需要
- 主应用:
- 配置
runtime.masterApp.apps
参数注册子应用
- 使用
useModuleApps
API 获取子应用实例并在组件中完成渲染
- 子应用:
所以插件中为你做了如下事情
- 帮助你通过
Garfish
运行时 API 自动注册子应用(主应用)
useModulesApps
函数的返回值提供了一个常驻的 DOM
节点供子应用挂载(主应用)
- 帮助你正确导出了
provider
(子应用)
- 帮助你正确设置了
basename
给 Modern.js
运行时提供 Router
实例,如果是自控式路由
或手动引入的 react-router-dom
那么需要从 App.tsx
的 props
中获取 basename
手动传递给引入的 Router 实例
(子应用)
常见问题
自查手册: https://www.garfishjs.org/issues/