当前位置: 首页 > news >正文

SingleSpa微前端基本使用以及原理

先说说singleSpa的缺点

  • 不够灵活 不能动态加载css文件
  • css不隔离
  • 没有js沙箱的机制 ( 没有全局对象 每次切换的应用 都是同一个window )

但是刚刚接触微前端 可以了解一下微前端的基础使用
qiankun微前端框架已经很成熟 也是基于singleSpa来实现的
点击跳转qiankun的基础使用

大致实现思路 (不了解微前端概念的可以去自行了解)

  • 首先在父应用注册一个应用
  • 当条件满足的时候(匹配路径) 会加载我们另一个子应用的脚本
  • 加载子应用用脚本的话
    – 那在我们子应用打包的时候 , 自身上就有一些类库了
  • 父应用加载到子应用的类库时候 就会调用子应用身上的一些方法了
    – 这个时候 类库就会把子应用整体的dom 放在( 挂载 )到父应用上面去
  • 而且我们要保证子应用自身引用的所有路径 都是相对于自身的绝对路径
    – 不然在父应用里使用子应用的一些操作 调用的是父应用的根路径 就会出问题

首先创建两个应用

一个子应用 各个父应用

在这里插入图片描述

我们需要父应用加载子应用 需要在子应用导出三个方法
bootstrap mount unmount ( SingleSpa的规定 )

vue的项目需要npm安装 Single-spa-vue
react的项目需要npm安装 Single-spa-react

初始化子应用

npm安装single-spa-vue

  • 配置main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'// 引入singleSpaVue的包
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = false//子应用不能直接挂载
// new Vue({   
//   router,
//   render: h => h(App)
// }).$mount('#app')// 而是封装成一个对象
const appOptions = {el:'#vue',  // 增加一个属性挂在到父应用的 id为vue的标签上router,render: h => h(App)
}// 把vue和上面这个对象传入进去  这个singleSpaVue就会返回vueLife
// vueLife是包装好的生命周期  对应的就是bootstrap mount unmount  这三个方法
const vueLife = singleSpaVue({Vue,appOptions
})//导出这三个方法  
//协议接入  我定好了这些方法  父应用会调用这些方法
export const bootstrap = vueLife.bootstrap
export const mount = vueLife.mount
export const unmount = vueLife.unmount
  • 我们需要父应用加载子应用 需要打包成一个个的lib去给父应用使用
  • 如何打包呢 在vue.config.js中配置
module.exports = {configureWebpack:{output:{// 给类库取一个名字library:'singleVue',// 指定模块类型  umd 会把打包后那三个属性挂在window上 //比如 window.bootstrap / window.mount / window.oumountlibraryTarget:'umd' },devServer:{port:10000 }}
}

初始化父应用

npm安装single-spa (不要加vue)

  • App.vue中处理结构
<template><div id="app"><!-- 路由中没写/vue这个路径  说明路由匹配不到  但是可以去匹配这个路由来加载子应用  --><router-link to="/vue">加载vue子应用</router-link><!-- 这个id = vue就是子应用main.js中el挂载的#vue --><div id="vue"></div></div>
</template>
  • main.js处理
import Vue from 'vue'
import App from './App.vue'
import router from './router'
// 固定导出两个方法  注册应用 / 开始应用
import {registerApplication,start} from 'single-spa'
Vue.config.productionTip = false// 注册应用  参数1 注册一个名字  参数2 一点要是个promise函数
registerApplication('myVueApp',async()=>{// 如果路径为 /vue  就会调用现在这个方法了   但是这个方法必须要导出子应用下的那三个方法 (不导出会报错) // 但是这个三个方法在哪里呢  请看下面的图片 具体写法先写如下// 动态创建script标签 把这个模块引入进来  (加载顺序要先加载公共的  再加载自己的 )await loadScript('http://localhost:10000/js/chunk-vendors.js')await loadScript('http://localhost:10000/js/app.js')// 这样就可以导出window上的lib包了  'singleVue'就是vue.config.js配置的包名 return window.singleVue //bootstrap mount onmount},// 参数3 用户切换到/vue路径下 需要加载刚刚定义的子应用location=>location.pathname.startsWith('/vue')
)// 处理上面参数2的promise
async function loadScript(url){// js加载是异步的 所以要用promisereturn new Promise((resole,reject)=>{let script = document.createElement('script')script.src = urlscript.onload = resole // 加载成功script.onerror = reject //加载失败document.head.appendChild(script) //把script放在html的head标签里 })
}// 开启应用
start()new Vue({router,render: h => h(App)
}).$mount('#app')

在这里插入图片描述

  • 这样就开启了基础的嵌入子应用
    在这里插入图片描述
  • 点击按钮后 ( 但是还有问题 )
  • css没有隔离 ( 使用到了子应用的css 导致标签就居中了 )
  • 点击子应用的路由 跳转会错误
    – 路径上的/vue会消失( 点击子应用的路由 但是跳转的是父应用的路由 )
    – 需要在子应用中虚拟一个路径
    在这里插入图片描述

给子路由配置基础路径

  • 子应用的router/index中
const router = new VueRouter({mode: 'history',// base: process.env.BASE_URL, //删除原本的//点击子应用的路由的时候 需要通过/vue去加载base: '/vue', routes
})
  • 但是还有个问题 每次点击子路由的时候 加载的是父应用上的路由
    – 我们需要操作子应用的时候 匹配的是子应用自身的路径
    – 解决方法 : 我们请求的每一个路由 都要加载的是自身的根路径才行
    -在子应用的main.js中配置
    主要看if(window.singleSpaNavigate){}后面的新增代码
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import singleSpaVue from 'single-spa-vue'
Vue.config.productionTip = falseconst appOptions = {el:'#vue',  router,render: h => h(App)
}const vueLife = singleSpaVue({Vue,appOptions 
})//加上了如下的判断
//如果父应用引用我的时候
if(window.singleSpaNavigate){// 动态的设置一个属性 打包的时候加上一个目录 目录就是自身的根路径// 这样的时候我们发请求的时候 都会把这个路径拼到最前面 变成一个绝对路径__webpack_public_path__ = 'http://localhost:10000/'
}
//我们还需要让子应用独立运行 (如果父应用没有引用我的时候)
if(!window.singleSpaNavigate){// 子应用独立运行的话 就是正常初始化vue了  这个挂载父应用的el就可以删除delete appOptions.el//可以正常初始化vue了  new Vue(appOptions).$mount('#app')
}export const bootstrap = vueLife.bootstrap
export const mount = vueLife.mount
export const unmount = vueLife.unmount

现在的话已经基础的实现了父应用嵌套子应用

并且子应用也可以独立运行了

在这里插入图片描述
在这里插入图片描述

相关文章:

  • vue的导入
  • HTML 01
  • requests模块的其他方法
  • HTML静态网页成品作业(HTML+CSS)——电影网首页网页设计制作(1个页面)
  • 力扣hot100:76.最小覆盖子串(滑动窗口)
  • Android UI:ViewTree中的操作
  • 惬意上手Redis
  • 使用Anaconda创建Python指定版本的虚拟环境
  • 富格林:揭秘应对暗箱操作正规技巧
  • 【Linux进阶之路】HTTP协议
  • ARTS Week 20
  • BJFU|大数据基础考前速记(含考试大纲与复习笔记)
  • Pygame教程07:键盘常量+键盘事件的2种捕捉方式
  • SQL: 触发器/存储过程/游标的操作
  • System类 --java学习笔记
  • C++入门教程(10):for 语句
  • flask接收请求并推入栈
  • javascript数组去重/查找/插入/删除
  • magento2项目上线注意事项
  • Rancher如何对接Ceph-RBD块存储
  • SpriteKit 技巧之添加背景图片
  • VUE es6技巧写法(持续更新中~~~)
  • Vue2.0 实现互斥
  • Vue2.x学习三:事件处理生命周期钩子
  • 对象管理器(defineProperty)学习笔记
  • 构造函数(constructor)与原型链(prototype)关系
  • 和 || 运算
  • 记录一下第一次使用npm
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 两列自适应布局方案整理
  • 前端技术周刊 2019-02-11 Serverless
  • 使用Tinker来调试Laravel应用程序的数据以及使用Tinker一些总结
  • 微服务核心架构梳理
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 交换综合实验一
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • (1)bark-ml
  • (27)4.8 习题课
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (四)JPA - JQPL 实现增删改查
  • (学习日记)2024.01.09
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .bat批处理(六):替换字符串中匹配的子串
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .NET处理HTTP请求
  • .NET企业级应用架构设计系列之技术选型
  • @Valid和@NotNull字段校验使用
  • [ 常用工具篇 ] POC-bomber 漏洞检测工具安装及使用详解
  • [ 隧道技术 ] 反弹shell的集中常见方式(四)python反弹shell
  • []串口通信 零星笔记