微前端乾坤的实现以及注意事项

2023-11-13

微前端乾坤

qiankun 是一个基于 single-spa 的微前端实现库,拥有的特点:JS沙箱,样式隔离,元素隔离,数据通信,预加载,HTML Entry。
qiankun与single-spa的区别有:
qiankun 是HTML Entry,single-spa是 JS Entry
qiankun 有JS沙箱隔离(js沙箱先检测window.Proxy,否则降级为window快照),CSS样式隔离用Shawdom;single-spa不带JS和CSS沙箱隔离,需要用户自己设计

2018年,single-spa诞生了,single-spa是一个小于5kb(gzip)npm包,用于协调微前端的挂载和卸载。只做两件事: 提供生命周期,并负责调度子应用的生命周期。挟持 url 变化,url 变化时匹配对应子应用,并执行生命周期流程。

用于前端微服务化的JavaScript前端解决方案 (本身没有处理样式隔离、js执行隔离) ,实现了路由劫持和应用加载。
特点:

(1)在同一页面上使用多个框架而无需刷新页面

(2)独立部署

(3)使用新框架编写代码,无需重写现有应用程序

(4)延迟加载代码以改善初始加载时间

(5)本身没有处理样式隔离、js执行隔离,共用同一个window

主应用

  1. 全新的界面设计 ,将会带来全新的写作体验;
  2. 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示;

子应用

  1. vue2适配
    在这里插入图片描述
    在这里插入图片描述

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

shadow dom自动实现样式隔离(类似于原生的video标签,它有默认的样式)
在这里插入图片描述
在这里插入图片描述

主应用配置

src/main.js 修改

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import { registerMicroApps, start } from "qiankun";
//注册子应用
// 微前端运行原理和spa非常相似
// 当匹配到activeRule的时候,请求获取entry资源,渲染到container中
registerMicroApps([
  {
    name: "vueapp1",
    entry: "//localhost:8031",// 子应用的html入口
    container: "#container",// 渲染到哪里
    activeRule: "/mypage1",// 路由匹配原则
  },
  {
    name: "vueapp2",
    entry: "//localhost:8032",
    container: "#container",
    activeRule: "/mypage2",
  },
]);
createApp(App).use(router).mount("#app");
start();

src/router 修改

import { createRouter, createWebHistory } from "vue-router";
import HelloWorld from "./components/HelloWorld";

const routes = [
  {
    path: "/",
    name: "home",
    component: HelloWorld,
  },
];
const router = createRouter({
  history: createWebHistory(),
  routes,
});

//主应用使用的嵌套路由
router.beforeEach((to, from, next) => {
  if (!window.history.state.current) window.history.state.current = to.fullPath;
  if (!window.history.state.back) window.history.state.back = from.fullPath;
  // 手动修改history的state
  return next();
});

export default router;

src/App.vue 修改

<template>
  <div>
    <img alt="Vue logo" src="./assets/logo.png" />
    <br />
    <router-link to="/">基座: Go to Home</router-link>
    <br />
    <router-link to="/mypage1">基座: 去子应用1</router-link>
    <br />
    <router-link to="/mypage2">基座: 去子应用2</router-link>
    <br />
    // 主应用路由渲染出口
    <router-view></router-view>
    // 微前端子应用渲染出口
    <div id="container"></div>
  </div>
</template>

子应用配置

vue.config.js(vue.webpack.js) 修改

const { name } = require("./package");
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
  transpileDependencies: true,
  devServer: {
    port: 8031,
    headers: {
      // 允许cors跨域
      "Access-Control-Allow-Origin": "*",
    },
  },
  configureWebpack: {
    output: {
      library: `${name}-[name]`,
      libraryTarget: "umd", // 把微应用打包成 umd 库格式
    },
  },
});

package.json eslint 增加全局变量

"eslintConfig": {
    ...
    "globals": {
      "__webpack_public_path__": true
    },
    ...
  },

src/public-path.js 修改
动态修改子项目图片等素材地址,子项目中图片地址一般是相对根域名的,但是嵌入到主项目中,需要改变为绝对子项目域名,不然找不到图片

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}

main.js - 2选1 - (vue2)修改

import "./public-path";
import Vue from "vue";
import App from "./App.vue";
import routes from "./router";
import VueRouter from "vue-router";

Vue.config.productionTip = false;

let router = null;
let instance = null;
function render(props = {}) {
  const { container } = props;

  router = new VueRouter({
    base: window.__POWERED_BY_QIANKUN__ ? "/mypage1/" : "/",
    mode: "history",
    routes,
  });
  instance = new Vue({
    router,
    render: (h) => h(App),
  }).$mount(container ? container.querySelector("#app") : "#app");
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
// 子应用接入qiankun
// 导出三个必要的生命周期钩子函数
// 渲染之前
// 渲染函数
// 卸载函数
export async function bootstrap() {
  console.log("[vue] vue app bootstraped");
}
export async function mount(props) {
  console.log("[vue] props from main framework", props);
  render(props);
}
export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
  router = null;
}

main.js - 2选1 - (vue3)修改

import './public-path';
import { createApp } from 'vue'
import App from './App.vue'
import routes from './router'
import { createRouter, createWebHistory } from 'vue-router';
import store from './store'

let router = null;
let instance = null;
let history = null;

function render(props = {}) {
    const { container } = props;
    let arr = routes.options.routes;
    console.log(arr)
    history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/app-vue3' : '/');
    router = createRouter({
        history,
        routes: routes.options.routes,
    });
    instance = createApp(App);
    instance.use(router);
    instance.use(store);
    instance.mount(container ? container.querySelector('#app') : '#app');
}

if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

export async function bootstrap() {
    console.log('%c%s', 'color: green;', 'vue3.0 app bootstraped');
}

function storeTest(props) {
    props.onGlobalStateChange &&
    props.onGlobalStateChange(
        (value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),
        true,
    );
    props.setGlobalState &&
    props.setGlobalState({
        ignore: props.name,
        user: {
            name: props.name,
        },
    });
}

export async function mount(props) {
    storeTest(props);
    render(props);
    instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;
    instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}

export async function unmount() {
    instance.unmount();
    instance._container.innerHTML = '';
    instance = null;
    router = null;
    history.destroy();
}


router.js - 2选1 - (vue2) 修改
这里只能导出配置了,不然每次加载子项目会是同一个vue-router对象

import Vue from "vue";
import VueRouter from "vue-router";
import HelloWorld from "./components/HelloWorld";
import Hello from "./components/Hello";
import World from "./components/World";

Vue.use(VueRouter);

const routes = [
  { path: "/", component: HelloWorld },
  { path: "/hello", component: Hello },
  { path: "/world", component: World },
];

export default routes;

router.js - 2选1 - (vue3) 修改


App.vue 修改

<template>
  <div id="app">
    <img alt="Vue logo" style="height: 40px" src="./assets/big.jpg" />
    <br />
    <router-link to="/">子应用1:首页</router-link>
    <br />
    <router-link to="/hello">子应用1: hello 页</router-link>
    <br />
    <router-link to="/world">子应用1:world 页</router-link>
    <br />
    <router-view></router-view>
  </div>
</template>

问题

1、主项目报错,主项目是 vue3 + vue-router@4
[Vue Router warn]: Error with push/replace State DOMException: Failed to execute ‘replaceState’ on ‘History’: A history state object with URL ‘http://localhost:8080undefined/’ cannot be created in a document with origin ‘http://localhost:8080’ and URL ‘http://localhost:8080/mypage1/’.
解决:在router.js中增加下面代码,页面跳转的时候一些内容的丢失。解决办法也查找了一些资料

//主应用使用的嵌套路由
router.beforeEach((to, from, next) => {
  if (!window.history.state.current) window.history.state.current = to.fullPath;
  if (!window.history.state.back) window.history.state.back = from.fullPath;
  // 手动修改history的state
  return next();
});

2、子项目 webpack_public_path not defined
解决: package.json 中增加全局变量 webpack_public_path

"eslintConfig": {
    ...
    "globals": {
      "__webpack_public_path__": true
    },
    ...
  },

点击查看原文链接
点击查看原文链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

微前端乾坤的实现以及注意事项 的相关文章

随机推荐

  • systemverilog的timescale作用域

    参考文献1 https www chipverify com verilog verilog timescale scope 在数字电路仿真过程中 如果没有模块本身没有指定timescale 则编译器本身可能插入一个默认的timescale
  • 什么是死亡之 Ping 攻击?

    死亡之 Ping 攻击是一种拒绝服务 DoS 攻击 攻击者旨在通过发送大于最大允许大小的数据包来破坏目标计算机 从而导致目标计算机冻结或崩溃 原始的死亡之 Ping 攻击如今并不常见 称为 ICMP 洪水攻击的相关攻击更为普遍 死亡之 Pi
  • AD PCB 封装 快速放置等间距焊盘的方法

    这个问题经常会用到 所以有必要总结一下 下面以制作29个焊盘为例 其实你可以随便设置的 划重点 先按E然后按A快捷键 设置数量和间距大小 先说一种通用的吧 用特殊粘贴来处理 具体的方法为 1 先放一个焊盘 选中后剪切掉 2 依次按下键盘上的
  • 电子科技大学软件工程期末复习笔记(二):软件过程

    目录 前言 重点一览 软件过程模型的定义 软件工程的中心与三要素 软件生存期模型 瀑布模型 快速原型模型 增量模型 螺旋模型 如何选择过程模型 能力成熟度模型的五个级别 过程和产品的关系 本章小结 前言 本复习笔记基于王玉林老师的课堂PPT
  • mysql数据库缺点_MySQL数据库的优缺点是什么

    MySQL数据库的优缺点 优点 体积小 速度快 总体拥有成本低 开源 支持多种操作系统 是开源数据库 提供的接口支持多种语言连接操作 MySql的核心程序采用完全的多线程编程 线程是轻量级的进程 它可以灵活地为用户提供服务 而不过多的系统资
  • OpenTSDB-时序数据库

    一 简介 OpenTSDB Open time series data base 时间序列数据库 顾名思义 就是以时间为标签存储数据 它的特点是能够提供最高 毫秒级精度 的时间序列数据存储 能够长久保存原始数据并且不失精度 但是OpenTS
  • 核心解读 - 2022版智慧城市数字孪生标准化白皮书

    核心解读 2022版智慧城市数字孪生标准化白皮书 前言 城市数字孪生基本概念 一 城市数字孪生概述 1 城市数字孪生内涵及概念模型 2 城市数字孪生典型特征 3 城市数字孪生相关方 4 城市数字孪生技术参考架构 5 城市数字孪生关键技术 二
  • windows双网卡时设置网络优先级

    前言 仅在win10测试可用 在工作中需要连接公司内网 有线 不可联网 访问外网时需要连接无线 同时接入这两个网络时 内网访问正常 外网无法访问 此时可以通过调整网络优先级及配置路由实现内外网同时访问 一般来说 内网的网段数量较少 我们可以
  • 史上最详细教你制作“U盘启动盘”重装Windows10系统

    前言 几个月前的小编自己的一台windows笔记本系统崩溃 当时我还不会重装系统 而且那台笔记本的性能实在是太差的 内存特别小的古董笔记本 现在换了新的电脑 我现在要做的是 依靠手里的这台电脑 通过制作U盘启动盘 来重装我的windows系
  • JSP基础_0800_Directive 编译期指令

    Directive 编译指令 编译期间的指令 格式 常见的Directive page include 以后常用 必须掌握 taglib 1 page的下面四个属性最常用 2 include属性
  • 1695 删除子数组的最大得分

    题目描述 给你一个正整数数组 nums 请你从中删除一个含有 若干不同元素 的子数组 删除子数组的 得分 就是子数组各元素之 和 返回 只删除一个 子数组可获得的 最大得分 如果数组 b 是数组 a 的一个连续子序列 即如果它等于 a l
  • vscode配置PHP调试xDebug

    一 安装XDebug环境 1 在PHP页面写上phpinfo 打印PHP信息 如下图 2 整个网页全新复制黏贴到 https xdebug org wizard 如下图 点击分析按钮 3 如下图 分析结果 按如下步骤操作即可 4 下载xde
  • 查看端口号被哪些进程所占用,如何根据PID查看其对应的程序

    查看端口号 在终端里面输入 netstat ano PID所对应的程序 首先按 shift Ctrl esc 任务管理器 状态 右键显示出PID 任务管理器可以搜索PID 找到对应的PID就知道端口号了 查询PID更快的方法 powersh
  • es6数组去重+找出去重的个数

    本Markdown编辑器使用 StackEdit 6 修改而来 用它写博客 将会带来全新的体验哦 分享es3去重 找出重复个数跟es6的 Array prototype unique3 function var res var json f
  • 学历不应该成为“枷锁”

    孔乙已是鲁迅笔下人物 穷困流倒还穿着象征读书人的长衫 迁腐 麻木 最近 大家自我调佩是 当代孔乙己 学历成为思想负担 找工作时高不成低不就 你可以从以下几个角度说说你对看法 一 你认为社会对于学历和职业之间的关系认知是怎样的 首先我认为社会
  • PowerDesigner中显示name, code,comment的解决方法 修正脚本,执行不会重复添加comment...

    Option Explicit ValidationMode True InteractiveMode im Batch Dim mdl the current model get the current active model Set
  • 虚拟机内搭建CTFd平台搭建及CTF题库部署,局域网内机器可以访问

    一 虚拟机环境搭建 1 安装docker git docker compose ubuntu sudo apt get update 更新系统 sudo apt get y install docker io 安装docker sudo a
  • zxing解析二维码demo

    源文件 cpp include funset hpp include
  • pvr 与 png 的内存占用

    原文链接 http blog sina com cn s blog 6fbe210701015j7z html Zwoptex 生成的 spritesheet 除了可以导出 png 格式的图片外还有 pvr 格式 pvr 格式是 iOS 的
  • 微前端乾坤的实现以及注意事项

    微前端乾坤 微前端乾坤 主应用 子应用 主应用配置 子应用配置 问题 微前端乾坤 qiankun 是一个基于 single spa 的微前端实现库 拥有的特点 JS沙箱 样式隔离 元素隔离 数据通信 预加载 HTML Entry qiank