微前端框架MicroApp
什么是微前端
微前端是一种类似于微服务的架构,是一种由独立交付的多个前端应用组成整体的架构风格,将前端应用分解成一些更小、更简单的能够独立开发、测试、部署的应用,而在用户看来仍然是内聚的单个产品。简单来说就是一个项目里可以内嵌多个子项目,子项目可以单独开发、部署并且技术框架无关。
使用场景
大规模企业级 Web 应用开发
跨团队及企业级应用协作开发
不知道大家有没有经历过俗称屎山的项目,就是用的技术比较老然后还堆积了很多业务要重构需要花很大成本, 我觉得这种场景就很适合使用微前端去解决。
MicroApp介绍
在micro-app
之前,业内已经有一些开源的微前端框架,比较流行的有2个:single-spa
和qiankun
single-spa
是通过监听 url change 事件,在路由变化时匹配到渲染的子应用并进行渲染,这个思路也是目前实现微前端的主流方式。同时single-spa
要求子应用修改渲染逻辑并暴露出三个方法:bootstrap
、mount
、unmount
,分别对应初始化、渲染和卸载,这也导致子应用需要对入口文件进行修改。因为qiankun
是基于single-spa
进行封装,所以这些特点也被qiankun
继承下来,并且需要对webpack配置进行一些修改。
micro-app
并没有沿袭single-spa
的思路,而是借鉴了WebComponent的思想,通过CustomElement结合自定义的ShadowDom,将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。并且由于自定义ShadowDom的隔离特性,micro-app
不需要像single-spa
和qiankun
一样要求子应用修改渲染逻辑并暴露出方法,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案。
micro-app
将所有功能都封装到一个类WebComponent组件中,从而实现在基座应用中嵌入一行代码即可渲染一个微前端应用。 同时micro-app
还提供了js沙箱
、样式隔离
、元素隔离
、预加载
、数据通信
、静态资源补全
、插件系统
一系列完善的功能。
micro-app
兼容所有框架以及脚手架构建工具包括Vite
、Nextjs
、Nuxtjs
。
WebComponent基本概念
WebComponent就是利用官方提供的原生API实现类似Vue、React的组件形式,它由三项主要技术组成,它们可以一起使用来创建封装功能的定制元素,可以在你喜欢的任何地方重用,不必担心代码冲突。
Custom elements(自定义元素): 一组JavaScript API,允许您定义custom elements及其行为,然后可以在您的用户界面中按照需要使用它们。
Shadow DOM(影子DOM) :一组JavaScript API,用于将封装的“影子”DOM树附加到元素(与主文档DOM分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。
HTML templates(HTML模板):
<template>
和<slot>
元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用。
写一个简单的组件
定义自定组件:
class MyButton extends HTMLElement { constructor () { super(); // 创建一个 shadow root const shadow = this.attachShadow({mode: 'open'}); const template = document.getElementById('mybutton'); const content = template.content.cloneNode(true); shadow.appendChild(content); } // 生命周期 // connectedCallback:当 custom element首次被插入文档DOM时,被调用。 // disconnectedCallback:当 custom element从文档DOM中删除时,被调用。 // adoptedCallback:当 custom element被移动到新的文档时,被调用。 // attributeChangedCallback: 当 custom element增加、删除、修改自身属性时,被调用。 connectedCallback() { console.log('Custom square element added to page.'); updateStyle(this); } disconnectedCallback() { console.log('Custom square element removed from page.'); } adoptedCallback() { console.log('Custom square element moved to new page.'); } attributeChangedCallback(name, oldValue, newValue) { console.log('Custom square element attributes changed.'); updateStyle(this); } } 复制代码
定义组件模板:
<template id="mybutton"> <style> button { color: white; background-color: #666; padding: 5px; } </style> <button>Add</button> </template> 复制代码
注册组件:
window.customElements.define('my-button', MyButton); 复制代码
使用组件:
<body> <my-button></my-button> </body> 复制代码
核心原理
MicroApp 的核心功能在CustomElement基础上进行构建,CustomElement用于创建自定义标签,并提供了元素的渲染、卸载、属性修改等钩子函数,我们通过钩子函数获知微应用的渲染时机,并将自定义标签作为容器,微应用的所有元素和样式作用域都无法逃离容器边界,从而形成一个封闭的环境。
概念图&对比图
基本使用
下面基座应用以React为例
基座应用
每个自定义标签micro-app
渲染后就是一个微前端的子应用,它的使用方式类似于iframe标签。 我们需要给标签传递三个基础属性:
name:名称
url:子应用页面地址
baseurl:baseurl是基座应用分配给子应用的路由前缀
// router.js import { BrowserRouter, Switch, Route } from 'react-router-dom' import ChildPage from './child-page' export default function AppRoute () { return ( <BrowserRouter> <Switch> // 非严格匹配,/child/* 都将匹配到ChildPage组件 // /child 就是分配给子应用的路由前缀baseroute <Route path='/child'> <ChildPage /> </Route> </Switch> </BrowserRouter> ) } export function ChildPage () { return ( <div> <h1>子应用</h1> <micro-app name='child-app' url='http://localhost:3000/' baseroute='/child' // 生命周期 onCreated={() => console.log('micro-app元素被创建')} onBeforemount={() => console.log('即将被渲染')} onMounted={() => console.log('已经渲染完成')} onUnmount={() => console.log('已经卸载')} onError={() => console.log('渲染出错')}> </micro-app> </div> )} 复制代码
子应用
如果子应用是多页面,只需要修改路由配置,添加路由前缀。 如下: window.__MICRO_APP_BASE_URL__是由基座应用下发的路由前缀,在非微前端环境下,这个值为undefined
React
import { BrowserRouter, Switch, Route } from 'react-router-dom' export default function AppRoute () { return ( <BrowserRouter basename={window.__MICRO_APP_BASE_ROUTE__ || '/'}> <Switch> ... </Switch> </BrowserRouter> ) } 复制代码
Vue2
// main.js import VueRouter from 'vue-router' import routes from './router' const router = new VueRouter({ mode: 'history', // ???? __MICRO_APP_BASE_ROUTE__ 为micro-app传入的基础路由 base: window.__MICRO_APP_BASE_ROUTE__ || process.env.BASE_URL, routes, }) 复制代码
完整案例:github.com/micro-zoe/m…
插件系统
微前端的使用场景都是比较复杂所以坑会比较多,MicroApp
提供了一套插件系统,每一个js文件都会经过插件系统,我们可以利用插件系统对这些js做一些特殊处理。
作者:直男
链接:https://juejin.cn/post/7054099370416799751