浅玩微前端
前言
这里不会大篇幅讲述微前端是啥,也没有很深入的知识点,只是一篇简单试玩微前端的文章,可能看完后什么都没学到,嘻嘻🙃🙃🙃。
- 什么是微前端?
类似微服务的概念,具有多个独立发布功能的web应用技术。详情链接
- 微前端的特点?
- 与技术栈无关
- 微应用可独立部署
- 每个微应用状态隔离
- 提出微前端概念的缘由?
当一个单体应用经过长时间的迭代、人员的变动,很可能变成一个巨大且难以维护的应用;而微前端架构旨在把巨石单体应用可拆为多个可独立部署的微应用,可组合使用,也可单体部署使用,可使各团队更加专注于自己的模块。
常见使用于 ToB 应用。
或许你遇到过这样的一个场景:你在网页上使用 iframe
嵌套了另一个网站,使当前网站使用 额外的功能,而被嵌套的网站,也是单独部署的。
可以把它理解为微前端的一种场景,但只是最终微前端架构都没有采用 iframe
来实现而已。为什么不使用iframe?
有兴趣可以阅读一下这两篇文章👇
Demo
demo 案例主要是使用 qiankun 阿里的一套微前端方案,有在 umi 中使用 和 在搭建的 webpack 中使用,其实都差不多😄。
qiankun 微前端方案个人理解
主程序负责中介者的角色,负责管理所有子应用,将子应用渲染到对应的dom。子应用是通过 html emtry 进来,因为 html 是一个天然的沙盒,可以隔离不同应用之间的变量或样式。
首先是主程序管理所有子应用的父路由,当匹配到某个路由时,加载子应用然后再把路由交给子应用去匹配。
子应用的打包方式原理是利用 打包插件库的形式,主页面类似以插件的形式加载子应用。
umi 中使用 qiankun
Umi 3 版本需要安装 @umijs/plugin-qiankun 插件,最新版 Umi 4 已经集成在 @umijs/max 中了
- 主应用安装
$ mkdir micro-web-demo && cd micro-web-demo
$ yarn create @umijs/umi-app
$ yarn add @umijs/plugin-qiankun -D
- 主应用配置
// .umirc.ts
export default {
qiankun: {
master: {
// 注册子应用信息
apps: [
{
name: 'app1', // 子应用名,唯一
entry: '//localhost:3000', // 入口文件
},
{
name: 'app2', // 唯一 id
entry: '//localhost:8080',
},
],
},
},
}
// config/routes.ts
// 这里使用自定义了 layout 和 将 .umirc.js 中抽出来
export default [
{
path: '/',
name: '主页',
component: '@/layouts/index',
routes: [
{
name: 'app1',
path: '/app1',
microApp: 'app1'
},
{
name: 'app2',
path: '/app2',
microApp: 'app2'
}
]
},
]
// src/layouts/index.tsx
import React, { useState } from 'react'
import { PageContainer, ProLayout } from '@ant-design/pro-components'
import { Link } from 'umi'
import routes from '../../config/routes'
interface Props {
children?: React.ReactNode
}
const Layout = (props: Props) => {
const { children } = props
return <ProLayout
style={{ height: '100vh' }}
route={{
routes: routes
}}
menuItemRender={(item) => {
return <Link
to={item.path}
>
{item.name}
</Link>
}}
>
<PageContainer>
{children}
</PageContainer>
</ProLayout>
}
export default Layout
- 子应用安装
# 这里使用了两种方式创建的子应用,1. create-react-app 2.vue-cli, 都是使用了最新的版本。
$ npx create-react-app micro-app-react
$ vue create micro-app-vue
- 子应用的配置可以查看 qiankun 项目实践 进行操作,已经写得很详细了。
⚠️ 注意点
因为 create-react-app
默认创建的 react 应用使用了最新的 版本,文档中有一些配置已经弃用或会报警告。react 18 版本更新日志
// src/index.js
// 这里 只展示需要修改 的代码
import ReactDOM from 'react-dom/client'
let root = null
function render(props) {
const { container } = props
// react 18 的新变化
root = ReactDOM.createRoot(
container
? container.querySelector('#root')
: document.querySelector('#root')
)
root.render(<App />)
}
export async function unmount(props) {
// 卸载,ReactDOM.unmountComponentAtNode 已弃用
root.unmount()
}
文档中使用了 @rescripts/cli
, 它好像只支持到 16.8 版本,建议使用 react-app-rewired
,配置如下👇
// config-overrides.js
const { name } = require('./package')
module.exports = {
webpack: (config) => {
config.output.library = `${name}-[name]`
config.output.libraryTarget = 'umd'
// webpack 5 jsonpFunction 改为 chunkLoadingGlobal
config.output.chunkLoadingGlobal = `webpackJsonp_${name}`
config.output.globalObject = 'window'
return config
},
devServer: (configFunction) => {
return function (proxy, allowedHost) {
const config = configFunction(proxy, allowedHost)
config.headers = {
'Access-Control-Allow-Origin': '*',
}
config.historyApiFallback = true
config.hot = false
// config.watchContentBase = false 废弃
config.liveReload = false
return config
}
},
}
同理 vue cli 4
默认创建的 vue 应用也是最新的版本,vue 3 更新日志
// src/main.js
function render(props = {}) {
const { container } = props
// 这里不是不行,只是简单使用,没有用到 vue router 就暂时注释了
// router = new VueRouter({
// base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
// mode: 'history',
// routes,
// });
// 这里才是要改的
instance = createApp(App)
instance.mount(
container ? container.querySelector('#app') : '#app'
)
}
export async function unmount() {
// 卸载
instance.unmount()
// qiankun 文档使用的是 $el, 因为 vue3 改了创建应用的方法,因此不能使用 $el
instance._container.innerHTML = ''
instance = null
// router = null
}
vue.config.js
中的 jsonpFunction
也需要改为 chunkLoadingGlobal
。
✴️ 提醒
public-path.js
须放在 entry.js 最上面。publicPath
最后,把各个应用跑起来就好啦 🎉🎉🎉
webpack 中使用 qiankun 可以看 完整案例代码中的 main-app-webpack
✈️