微前端--single-spa

微前端

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
使用微前端的挑战: 子应用切换,应用相互隔离,互补干扰,子应用之前的通信,多个子应用并存,用户状态的存储,免登。

常用技术方案

路由分发式微前端

通过http服务的反向代理

http {server {listen 80;server_name xxx.xxx.com;location /api/ {proxy_pass http://localhost:3001/api    }location /web/admin {proxy_pass http://localhost:3002/api}location / {proxy_pass /;}}
}

实现简单,不需要对现有应用进行改造,和技术栈无关。
切换应用的时候,浏览器都需要重新加载页面。

iframe

html的标签
实现简单,css和js隔离,互不干扰。全局上下文完全隔离,内存变量不共享,子应用之间的通信,数据同步过程比较复杂,对seo不友好。切换应用的时候,浏览器都需要重新加载页面。

single-spa

在single-spa方案中,应用被分为两类:基座应用和子应用。
single-spa 会在基座应用中维护一个路由注册表,每个路由对应一个子应用。基座应用启动以后,当我们切换路由时,如果是一个新的子应用,会动态获取子应用的 js 脚本,然后执行脚本并渲染出相应的页面;如果是一个已经访问过的子应用,那么就会从缓存中获取已经缓存的子应用,激活子应用并渲染出对应的页面。

// 基座
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router';
const  { registerApplication, start } =  require('single-spa');Vue.use(VueRouter)Vue.config.productionTip = false// 接入 single-spa 的标志
window.__SINGLE_SPA__ = trueconst router = new VueRouter({mode: 'history',routes: []
});// 远程加载子应用
function createScript(url) {return new Promise((resolve, reject) => {const script = document.createElement('script')script.src = urlscript.onload = resolvescript.onerror = rejectconst firstScript = document.getElementsByTagName('script')[0]firstScript.parentNode.insertBefore(script, firstScript)})
}
// 加载子应用
function loadApp(url, globalVar, entrypoints) {return async () => {for(let i = 0; i < entrypoints.length; i++) {await createScript(url + entrypoints[i])}return window[globalVar]}
}
// 子应用路由注册表
const apps = [{// 子应用名称name: 'app1',// 子应用加载函数app: loadApp('http://localhost:8081', 'app1', [ "/js/chunk-vendors.js", "/js/app.js" ]),// 当路由满足条件时(返回true),激活(挂载)子应用activeWhen: location => location.pathname.startsWith('/app1'),// 传递给子应用的对象customProps: {}},{name: 'app2',app: loadApp('http://localhost:8082', 'app2', [ "/js/chunk-vendors.js", "/js/app.js" ]),activeWhen: location => location.pathname.startsWith('/app2'),customProps: {}},{// 子应用名称name: 'app3',// 子应用加载函数app: loadApp('http://localhost:3000', 'app3', ["/main.js"]),// 当路由满足条件时(返回true),激活(挂载)子应用activeWhen: location => location.pathname.startsWith('/app3'),// 传递给子应用的对象customProps: {}}
]// 注册子应用
for (let i = apps.length - 1; i >= 0; i--) {registerApplication(apps[i])
}new Vue({router,render: h => h(App),mounted() {// 启动start()},
}).$mount('#app')
  • name: 子应用的唯一表示
  • activeWhen: 子应用激活的条件,当url发生变化的升级后,会遍历执行注册的子应用的activeWhen方法,当activeWhen返回的是true,对应的子应用就会被激活
  • app: 用户获取子应用提供给基座应用的生命周期,bootstrap mount unmount等。基座应用切换子应用时,也是同样的操作,即先执行上一个子应用的 unmount 操作,然后再执行下一个子应用的 mount 操作。因此就需要子应用提供 mount、unmount 等生命周期方法,供基座应用调用。和单页应用的懒加载一样,基座应用在激活子应用时,如果子应用是首次激活,就会执行 app 方法,动态去加载子应用的入口 js 文件,然后执行,得到子应用的生命周期方法。
  • customProps: 子应用激活的时候,可以传递给子应用的自定义属性,是一个对象
// index.jsimport Vue from 'vue'
import App from './App.vue'Vue.config.productionTip = falseconst appOptions = {render: (h) => h(App)
};let vueInstance;// 子应用没有接入 single-spa
if (!window.__SINGLE_SPA__) {new Vue(appOptions).$mount('#app')
}// 提供 bootstrap 生命周期方法
export function bootstrap () {console.log('app1 bootstrap')return Promise.resolve().then(() => {});
}
// 提供 mount 生命周期方法
export function mount (props) {console.log('app1 mount', props)return Promise.resolve().then(() => {vueInstance = new Vue(appOptions)vueInstance.$mount('#microApp')})
}// 提供 unmount 生命周期方法
export function unmount () {console.log('app1 unmount')return Promise.resolve().then(() => {if (!vueInstance.$el.id) {vueInstance.$el.id = 'microApp'}vueInstance.$destroy()vueInstance.$el.innerHTML = ''})
}// 提供 update 生命周期方法
export function update () {console.log('app1 update');
}

通常通过webpack构建工具生成的js脚本,表现形式都是iiff,就是立即执行函数表达式。各子应用对应的脚本执行的时是相互隔离的,如果是这样,基座应用在激活子应用的时候,是无法获取到子应用的生命周期方法的,也无法挂载子应用。添加libaray,libarayTarget配置项,将子应用入口文件的返回值就是生命周期方法暴露给window,这样基座应用就可以从window中获取子应用的生命周期的方法。

// 项目的构建脚本
module.exports = {configureWebpack: {...publicPath: 'http://localhost:8081'output: {library: 'app1',   libraryTarget: 'var'}    }
}
  • 单页应用的路由切换功能是基于window.history(window.location.hash)实现。在单页面应用中,会给window对象注册popstate(hashchange)事件,在callback中,添加页面切换的逻辑,当通过执行 pushState(replaceState) 方法、修改 hash 值、使用浏览器前进后退(go、back、forward)功能改变 url 时,会触发 popstate(hashchange) 事件,然后切换页面。
  • 基座应用加载执行 single-spa 时,也会给 window 对象注册 popstate (hashchange) 事件, popstate(hashchange) 的 calback 中,就是激活子应用的逻辑。当基座应用通过执行pushState(replaceState)、修改 hash、使用浏览器前进后退(go、back、forward)功能的方式修改 url 时,popstate(hashchange) 就会触发,相应的子应用的激活逻辑就会执行。
// 通过原生构造函数 - popStateEvent 创建一个popstate事件对象
function createPopStateEvent(state, originalMethodName) {var evt;try {evt = new PopStateEvent("popstate", {state: state    })} catch(err) {evt = document.createEvent('popstateevent')evt.initPopStateEvent("popstate", false, false, state)}evt.singleSpa = trueevt.singleSpaTrigger = originalMethodNamereturn evt
}
// 重写 updateState、replaceState 方法,通过 window.dispatchEvent 方法,手动触发 popstate 事件
function patchedUpdateState(updateState, methodName) {return function () {var urlBefore = window.location.href;var result = updateState.apply(this, arguments);var urlAfter = window.location.href;if (!urlRerouteOnly || urlBefore !== urlAfter) {window.dispatchEvent(createPopStateEvent(window.history.state, methodName));}return result;};
}
// 重写 pushState 方法
window.history.pushState = patchedUpdateState(window.history.pushState, "pushState");
// 重写 replaceState 方法
window.history.replaceState = patchedUpdateState(window.history.replaceState, "replaceState");
...
const router = new VueRouter({mode: 'history',base: '/app1',routes: [{path: '/foo',name: 'foo',component: {...}}, {path: '/bar',name: 'bar',component: {...}}]
})
...

application 模式下,single-spa 的工作流程,application 模式下,我们需要先通过registerApplication 注册子应用,然后在基座应用挂载完成以后执行 start 方法, 这样基座应用就可
以根据 url 的变化来进行子应用切换,激活对应的子应用。
在这里插入图片描述

parcel模式下,single-spa的工作流程。mountRootParcel 方法会返回一个parcel实例对象,内部包含update、unmount 方法。当我们需要更新组件时,直接调用parcel对象的update方法,就可以触发组件的update生命周期方法;当我们需要卸载组件时,直接调用parcel对象的unmount方法。在执行mountRootParcel 方法时,传入的第二个参数,会作为组件 mount 生命周期方法的入参;在执行 parcel.update 方法时,传入的参数,会作为组件 update 生命周期方法的入参。

子应用是否被挂载

  • NOT_LOADED 未加载/待加载
  • LOAD_SOURCE_CODE 加载源代码
  • NOT_SOURCE_CODE 未启动/待启动
  • BOOTSTRAPPING 子应用启动中
  • NOT_MOUNTRED 为挂载/待挂载
  • MOUNTING 子应用挂载中
  • UNMOUNTING 需要卸载
  • UNMOUNTED 已经卸载
  • LOAD_ERROR 子应用加载失败
传参

父组件和parcel组件的通信
mount 阶段,父组件在执行 mountRootParcel 时,可以将要传递给 parcel 组件的值作为第二个参数,这个参数会作为 parcel 组件 mount 方法执行时的入参,这样 parcel 组件就可以拿到父组件传递的值。update 阶段也一样,父组件执行 parcel.update 时,传入的参数会作为 parcel 组件 update 方法执行时的入参。
基座应用和子组件之间的通信
基座应用在定义路由注册表的时候,会给每个子应用定义一个customProps,这个customoProps会作为子应用mount方法的入参,在子应用中, customProps(或者 customProps 里面的某个值) 可以作为子应用的共享状态(使用 vuex、mobx、redux 等)。这样,当基座应用修改 customProps 时,子应用就可接受到通知,然后更新。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/875202.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人机搭载无人机反制设备可行性分析

一、引言 随着无人机技术的飞速发展&#xff0c;无人机在各个领域的应用越来越广泛。然而&#xff0c;无人机的不当使用也可能带来安全隐患和隐私问题。因此&#xff0c;无人机反制设备应运而生&#xff0c;用于对非法或危险无人机进行干扰和控制。本文将对无人机搭载无人机反…

简单的git分支mergepush权限设定

简单的git分支merge&push权限设定 1. 需求 公司的分支很多&#xff0c;主要的有master分支&#xff0c;很多的业务需求分支&#xff0c;开发测试分支(uat,uat2,sit,sit2)&#xff0c;这些分支当前是谁都可以进行提交&#xff0c;但是如果在分支上直接修改&#xff0c;或者…

Sentinel隔离、降级、授权规则详解

文章目录 Feign整合Sentinel线程隔离熔断降级授权规则自定义异常结果 上一期教程讲解了 Sentinel 的限流规则&#xff1a; Sentinel限流规则&#xff0c;这一期主要讲述 Sentinel 的 隔离、降级和授权规则 虽然限流可以尽量避免因高并发而引起的服务故障&#xff0c;但服务还…

R语言统计分析——数据管理4

参考资料&#xff1a;R语言实战【第2版】 1、数学函数 abs(x)&#xff1a;绝对值 sqrt(x)&#xff1a;平方根 ceiling(x)&#xff1a;不小于x的最小整数 floor(x)&#xff1a;不大于x的最大整数 trunc(x)&#xff1a;向0的方向截取x中的整数部分 round(x,digitsn)&#…

参加可观测性Observability Foundation认证培训,您有哪些收益?

一、可观测性认证培训的内容 作为SRE&#xff08;站点可靠性工程&#xff09;课程体系的最新发展&#xff0c;可观测性&#xff08;Observability&#xff09;认证课程介绍了一系列结合应用程序生命周期和复杂体系架构中推进可观测性的核心概念和实践。为关注全栈可观测性&…

涉及VPN、金融、健康服务等类型应用上架政策突变

大家好&#xff0c;我是牢鹅&#xff01;今天为大家分享Google Play 2024年7月17日下发的政策更新&#xff0c;此次政策更新距上次&#xff08;4月5日&#xff09;政策大更新仅过去三个月。前段时间牢鹅跟谷歌的人有聊过&#xff0c;今年他们的目标很明确&#xff0c;提高开发者…

Django执行ORM时打印SQL语句

settings中添加LOGGING相关日志配置 LOGGING {version: 1,disable_existing_loggers: False,handlers: {console:{level:DEBUG,class:logging.StreamHandler,},},loggers: {django.db.backends: {handlers: [console],propagate: True,level:DEBUG,},}}批量查询DEMO&#xf…

Docker————数据卷容器,容器互联,镜像创建

1、Docker的数据管理 管理Docker容器中的数据&#xff0c;主要有两种方式&#xff1a;数据卷&#xff08;Data Volumes&#xff09;和数据卷容器&#xff08;DataVolumes Containers&#xff09;. docker run [-i -t] [--name 容器名] 镜像名&#xff1a;标签 [容器启动命令]…

线下陪玩平台搭建系统小程序线下陪玩到家软件系统搭建开发

在当今的陪玩行业中&#xff0c;一种被称为“豺狼虎豹”的现象正在悄然兴起&#xff0c;那就是陪玩师接私单的行为。因为它不仅影响了平台的正常运营&#xff0c;还可能导致高质量客户的流失。然而&#xff0c;这个这种行为对于平台来说无疑是一种巨大的挑战&#xff0c;问题并…

vue3.0学习笔记(三)——计算属性、监听器、ref属性、组件通信

1. computed 函数 定义计算属性&#xff1a; computed 函数&#xff0c;是用来定义计算属性的&#xff0c;计算属性不能修改。 计算属性应该是只读的&#xff0c;特殊情况可以配置 get set 核心步骤&#xff1a; 导入 computed 函数 执行函数 在回调参数中 return 基于响应…

opencascade AIS_Line源码学习

前言 AIS_Line 是 OpenCASCADE 库中的一个类&#xff0c;用于表示和操作三维直线。它可以通过几何线&#xff08;Geom_Line&#xff09;或者两个几何点&#xff08;Geom_Point&#xff09;来初始化。 方法 1 //! 初始化直线 aLine。 Standard_EXPORT AIS_Line(const Handl…

JavaScript(14)——DOM

Web API 作用&#xff1a;就是使用JS去操作html和浏览器 分类&#xff1a;DOM&#xff08;文档对象模型&#xff09;、BOM&#xff08;浏览器对象模型&#xff09; DOM DOM是用来呈现以及与任意HTML或XML文档交互的API&#xff0c;简单来说就是操作网页的内容。 DOM树 将H…

计算机视觉与图像分类:技术原理、应用与发展前景

引言 随着科技的不断进步&#xff0c;计算机视觉逐渐成为了人工智能领域的重要分支之一。计算机视觉旨在让计算机具备“看懂”图像和视频的能力&#xff0c;从而理解和分析视觉信息。作为计算机视觉中的一个关键任务&#xff0c;图像分类涉及将输入的图像归类到预定义的类别中&…

学习记录day18——数据结构 算法

算法的相关概念 程序 数据结构 算法 算法是程序设计的灵魂&#xff0c;结构式程序设计的肉体 算法&#xff1a;计算机解决问题的方法护额步骤 算法的特性 1、确定性&#xff1a;算法中每一条语句都有确定的含义&#xff0c;不能模棱两可 2、有穷性&#xff1a;程序执行一…

35_YOLOX网络详解

1.1 简介 YOLOX是YOLO系列&#xff08;You Only Look Once&#xff09;目标检测模型的一个最新变种&#xff0c;由阿里云团队和旷视科技在2021年提出。YOLO系列以其快速、准确的目标检测能力而闻名&#xff0c;而YOLOX在此基础上进行了多方面的改进和优化&#xff0c;旨在提供…

机器学习数学基础(2)--最大似然函数

声明&#xff1a;本文章是根据网上资料&#xff0c;加上自己整理和理解而成&#xff0c;仅为记录自己学习的点点滴滴。可能有错误&#xff0c;欢迎大家指正。 在机器学习和统计学领域中&#xff0c;似然函数&#xff08;Likelihood Function&#xff09;是一个至关重要的概念。…

AIGC的神秘面纱——利用人工智能生成内容改变我们的生活

近年来&#xff0c;人工智能生成内容&#xff08;AIGC&#xff09;正在迅速改变我们与数字世界互动的方式。从自动写作到图像生成&#xff0c;AIGC正逐渐走进我们的日常生活。它不仅提高了效率&#xff0c;还为创意和商业活动带来了新的可能性。让我们一起来探索AIGC的世界&…

解读 IP 地址定位

你是否好奇众多平台推出的 IP 归属地功能是如何确定的位置&#xff1f;其实这些说起来并不难。接下来让我来给你们说一下其中的“奥秘”吧~ 一、IP 定位背后的原理 首先&#xff0c;从“IP 地址”开始。因为每个联网设备在接入网络时都会被分配一个独一无二的 IP 地址。根据这…

通信原理思科实验三:无线局域网实验

实验三 无线局域网实验 一&#xff1a;无线局域网基础服务集 实验步骤&#xff1a; 进入物理工作区&#xff0c;导航选择 城市家园; 选择设备 AP0&#xff0c;并分别选择Laptop0、Laptop1放在APO范围外区域 修改笔记本的网卡&#xff0c;从以太网卡切换到无线网卡WPC300N 切…

3.多租户调研1

https://gitee.com/xiaoqiangBUG/hello-ruoyi-cloud.git 1.mybatis plus 的插件 TenantLineInnerInterceptor 是 MyBatis Plus 框架中的一个拦截器&#xff0c;它用于实现多租户系统的数据隔离。在多租户应用中&#xff0c;不同的租户应该只能访问到自己的数据&#xff0c;而…