浅玩微前端
前言
这里不会大篇幅讲述微前端是啥,也没有很深入的知识点,只是一篇简单试玩微前端的文章,可能看完后什么都没学到,嘻嘻🙃🙃🙃。
- 什么是微前端?
类似微服务的概念,具有多个独立发布功能的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
- 主应用配置
export default { qiankun: { master: { // 注册子应用信息 apps: [ { name: 'app1', // 子应用名,唯一 entry: '//localhost:3000', // 入口文件 }, { name: 'app2', // 唯一 id entry: '//localhost:8080', }, ], }, },}
// 这里使用自定义了 layout 和 将 .umirc.js 中抽出来export default [ { path: '/', name: '主页', component: '@/layouts/index', routes: [ { name: 'app1', path: '/app1', microApp: 'app1' }, { name: 'app2', path: '/app2', microApp: 'app2' } ] },]
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 版本更新日志
// 这里 只展示需要修改 的代码import ReactDOM from 'react-dom/client'
let root = nullfunction 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
,配置如下👇
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 更新日志
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
✈️