【微前端】微前端笔记(二)

前言

  • 第一篇的single-spa模式存在样式没有隔离,以及需要手动引入js的问题。

样式隔离方案

  • 主应用与子应用解决样式隔离一般有以下几种方案:
  • BEM 即约定项目前缀
  • CSSMoudule 打包时生成不冲突的选择器
  • shadowDom 真正意义上隔离
  • css in js

shadow dom

  • 看一个例子:

<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Documenttitle>
	head>
	<body>
		<div>
			<p>hellow worldp>
			<div id="shadow">div>
		div>
	body>
	<script>
		let shadowDom = shadow.attachShadow({ mode: "closed" });
		let p = document.createElement("p");
		p.innerHTML = "yehuozhili";
		let style = document.createElement("style");
		style.textContent = `
            p{color:red};
        `;
		shadowDom.appendChild(style);
		shadowDom.appendChild(p);
	script>
html>
  • 其中影子dom 里放入了样式表,整个document有2个p标签,但是受影响的只有影子标签的p ,外界不受影响。

沙箱方案

  • proxy
  • 快照
  • 来看一个快照的例子:

<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>Documenttitle>
	head>
	<body>
		<div>
			<p>hellow worldp>
			<div id="shadow">div>
		div>
	body>
	<script>
		class SnapshotSandbox {
			constructor() {
				this.proxy = window;
				this.modifyPropsMap = {};
				this.active(); //先走了active 并且把window上属性存到了windowsnapshot上
			}
			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() {
				//失活 就是当前和开始进入的快照进行比对,不一样就存到修改map,同时恢复开始进入的快照
				for (const prop in window) {
					if (window.hasOwnProperty(prop)) {//不一样的属性存到修改map里
						if (window[prop] !== this.windowSnapshot[prop]) {
							this.modifyPropsMap[prop] = window[prop];
							window[prop] = this.windowSnapshot[prop];
						}
					}
				}
			}
		}

		let sandbox = new SnapshotSandbox();
		((window) => {
			window.a = 1;
			window.b = 2;
			console.log(window.a, window.b);
			sandbox.inactive();
			console.log(window.a, window.b);
			sandbox.active();
			console.log(window.a, window.b);
		})(sandbox.proxy);
	script>
html>
  • 其实就是浅比较window然后恢复就完了。
  • 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];//这里就是取不到会找window的
            }
        });
        this.proxy = proxy
    }
}
let sandbox1 = new ProxySandbox();
let sandbox2 = new ProxySandbox();
window.a = 1;
((window) => {
    window.a = 'hello';
    console.log(window.a)
})(sandbox1.proxy);
((window) => {
    window.a = 'world';
    console.log(window.a)
})(sandbox2.proxy);

乾坤

  • 乾坤是基于single-spa进行封装的
  • 首先,我们创建3个应用,qiankun-base,qiankun-react,qiankun-vue
  • 编写base
  • 安装element-ui 与乾坤

main.js

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import "element-ui/lib/theme-chalk/index.css";
import ElementUI from "element-ui";
import { registerMicroApps, start } from "qiankun";
Vue.config.productionTip = false;

Vue.use(ElementUI);

const apps = [
	{
		name: "vueApp", //应用名
		entry: "//localhost:10000", //默认会加载这个html,解析里面的js 动态的执行(子应用必须支持跨域)
		container: "#vue", //容器名
		activeRule: "/vue", //激活路径
	},
	{
		name: "reactApp",
		entry: "//localhost:20000",
		container: "#react",
		activeRule: "/react",
	},
];

registerMicroApps(apps); //注册应用
start(); //开启
new Vue({
	router,
	render: (h) => h(App),
}).$mount("#app");

app.vue