微前端简要介绍

最近由于项目需要,有幸接触到微前端MicroApp,下面是我对微前端的一些理解给大家做一个分享

微前端是什么

微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。

为什么要用微前端

1、拆分和细化

当下前端领域,单页面应用(SPA)是非常流行的项目形态之一,而随着时间的推移以及应用功能的丰富,单页应用变得不再单一而是越来越庞大也越来越难以维护,往往是改一处而动全身,由此带来的发版成本也越来越高。微前端的意义就是将这些庞大应用进行拆分,并随之解耦,每个部分可以单独进行维护和部署,提升效率。

2、整合历史系统进行迭代

在不少的业务中,存在很多历史项目,这些项目大多以采用老框架类似的B端管理系统为主,介于日常运营,这些系统需要结合到新框架中来使用还不能抛弃,对此我们也没有理由浪费时间和精力重写旧的逻辑。而微前端可以将这些系统进行整合,在基本不修改来逻辑的同时来同时兼容新老两套系统并行运行。

3、对于项目迭代式重构

对于比较多的项目,或许因为以前的技术规划或者技术选型,导致现今比较落后,对一个项目健康发展起到阻碍作用,项目维护成本过高但是一次性重构成本过大,我们选择迭代式重构,在业务迭代中对项目进行重构,对业务也会理解更加透彻。这样微前端就能很好的嵌入进来;

4、多个项目组业务耦合

面对多个产品线,经常出现业务交叉,不同的同时会在例外一个项目组的项目中开发,使得手上的项目使得项目管理混乱,尤其面对一些库的依赖升级,如果其他组成员未知晓,可能导致一些未知问题;

微前端实现方案

iframe嵌套:

众所周知,iframehtml提供的标签,能加载其他web应用的内容,并且它能兼容所有的浏览器,因此,你可以用它来加载任何你想要加载的web应用。iframe最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。 但是,最大的问题就是在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来开发体验、产品体验的问题。

组合式应用路由分发

每个子应用独立构建和部署,运行时由父应用进行路由管理,应用加载,启动,卸载,以及通信机制。

该方案的核心是“主从”思想,即包括一个基座(MainApp)应用和若干个微(MicroApp)应用,基座应用大多数是一个前端SPA项目,主要负责应用注册,路由映射,消息下发等,而微应用是独立前端项目,这些项目不限于采用React,Vue,Angular或者JQuery开发,每个微应用注册到基座应用中,由基座进行管理,但是如果脱离基座也是可以单独访问。

Web Components

Web Components 是一套不同的技术,允许您创建可重用的定制元素(它们的功能封装在您的代码之外)并且在您的 web 应用中使用它们。主要包含三大属性:

  • Custom elements(自定义元素):一组 JavaScript API,允许您定义 custom elements 及其行为,然后可以在您的用户界面中按照需要使用它们。

  • Shadow DOM(影子 DOM)、:一组 JavaScript API,用于将封装的“影子”DOM 树附加到元素(与主文档 DOM 分开呈现)并控制其关联的功能。通过这种方式,您可以保持元素的功能私有,这样它们就可以被脚本化和样式化,而不用担心与文档的其他部分发生冲突。

  • HTML templates(HTML 模板): [<template>](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/template)[<slot>](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/slot) 元素使您可以编写不在呈现页面中显示的标记模板。然后它们可以作为自定义元素结构的基础被多次重用

基于webpack5 module Federation

多个独立的构建可以形成一个应用程序。这些独立的构建不会相互依赖,因此可以单独开发和部署它们。 这通常被称为微前端,但并不仅限于此。 它的主要功能是我们可以将项目中的部分组件或全部组件暴露给外侧使用。我们也可以引用其他项目中暴露的组件,从而实现模块的复用。

其他:Nginx路由转发

single-spa

提供生命周期概念,并负责调度子应用的生命周期 挟持 url 变化事件和函数,url 变化时匹配对应子应用,并执行生命周期流程

首先我们需要用importmap在根项目中引入所有的模块文件和子项目,从而在其余项目中可以进行模块的引用。因为浏览器的不支持import,需要引入system.js

注册子应用

single-spa 里最重要的 API:registerApplication

singleSpa.registerApplication({ name:'navbar', // 子应用名app: () => System.import('navbar'), // 如何加载你的子应用activeWhen: location => true, // url 匹配规则,表示啥时候开始走这个子应用的生命周期//activeWhen: location => location.pathname.startsWith('/app1') customProps: { // 自定义 props,从子应用的 bootstrap, mount, unmount 回调可以拿到 authToken: 'something'}}) singleSpa.start() // 启动主应用

执行生命周期

const vueLifecycles = singleSpaVue({Vue, appOptions: {render: (h) => h(App), router,},});export const bootstrap = vueLifecycles.bootstrap;export const mount = vueLifecycles.mount;export const unmount = vueLifecycles.unmount;

qiankun

相比single-spaqiankun他解决了JS沙盒环境,不需要手动的去写调用子应用JS,加载采用的HTML Entry方式

JS Entry 的方式通常是子应用将资源打成一个 entry script,但这个方案的限制也颇多,如要求子应用的所有资源打包到一个 js bundle 里,包括 css、图片等资源。除了打出来的包可能体积庞大之外的问题之外,资源的并行加载等特性也无法利用上。

HTML Entry 则更加灵活,直接将子应用打出来 HTML 作为入口,主框架可以通过 fetch html 的方式获取子应用的静态资源,同时将 HTML document 作为子节点塞到主框架的容器中。这样不仅可以极大的减少主应用的接入成本,子应用的开发方式及打包方式基本上也不需要调整,而且可以天然的解决子应用之间样式隔离的问题(后面提到)。

基座

注册

import { registerMicroApps, start } from "qiankun";const apps = [{ name: "vueApp", // 应用的名字 entry: "//localhost:10000",//加载的html路径 container: "#vue", // 容器名 activeRule: "/vue", // 激活的路径},{ name: "reactApp", entry: "//localhost:20000", container: "#react", activeRule: "/react",},];registerMicroApps(apps); // 注册应用start(); // 开启

子项目

import Vue from 'vue'import App from './App.vue'import router from './router'// Vue.config.productionTip = falselet instance = nullfunction render(props) { instance = new Vue({ router,render: h => h(App)}).mount('#app'); // 这里是挂载到自己的html中 基座会拿到这个挂载后的html 将其插入进去}if (window.__POWERED_BY_QIANKUN__) { // 动态添加publicPath __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;}if (!window.__POWERED_BY_QIANKUN__) { // 默认独立运行render();}export async function bootstrap(props) {};export async function mount(props) {render(props)}export async function unmount(props) { instance.destroy();}

子项目打包配置

module.exports = { devServer:{ port:10000,// 需要允许跨域 headers:{'Access-Control-Allow-Origin':'*'}}, configureWebpack:{ output:{ library:'vueApp', libraryTarget:'umd'}}}

css隔离方案

子应用之间样式隔离

  • Dynamic Stylesheet 动态样式表,当应用切换时移除老应用样式,添加新应用样式

主应用和子应用之间的样式隔离

  • BEM (Block Element Modifier) 约定项目前缀

  • CSS-Modules 打包时生成不冲突的选择器名

  • Shadow Dom 真正意义上的隔离

js沙箱机制

  • 快照沙箱,在应用沙箱挂载或卸载时记录快照,在切换时依据快照恢复环境 (无法支持多实例)

class SnapshotSandbox{constructor(){this.proxy = window; this.modifyPropsMap = {}; this.active();}active(){ // 激活this.windowSnapshot = {}; // 拍照 for(const prop in window){if(window.hasOwnProperty(prop)){this.windowSnapshot[prop] = window[prop];}}Object.keys(this.modifyPropsMap).forEach(p=>{window[p] = this.modifyPropsMap[p];})}inactive(){ // 失活for(const prop in window){if(window.hasOwnProperty(prop)){if(window[prop] !== this.windowSnapshot[prop]){this.modifyPropsMap[prop] = window[prop];window[prop] = this.windowSnapshot[prop]}}}}}

  • Proxy 代理沙箱,不影响全局环境

class ProxySandbox {constructor() {const rawWindow = window;const fakeWindow = {}const proxy = new Proxy(fakeWindow, {set(target, p, value) { target[p] = value; return true},get(target, p) {return target[p] || rawWindow[p];}});this.proxy = proxy }}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容