微前端应用隔离
微前端中 CSS 和 JavaScript 的隔离方案
问题
微前端架构中,如何实现主应用与微应用、微应用与微应用之间的隔离?
解答
应用隔离主要包括 CSS 样式隔离和 JavaScript 执行环境隔离两个方面。
CSS 隔离
主应用与微应用之间
当主应用和微应用同屏渲染时,样式可能相互污染。可以采用以下方案:
- CSS Module:模块化的 CSS 方案
- 命名空间:给每个微应用添加特定前缀
使用 webpack 的 postcss 插件可以在打包时自动添加前缀:
// postcss.config.js
module.exports = {
plugins: [
require('postcss-prefix-selector')({
prefix: '.micro-app-prefix',
exclude: ['.ignore-prefix']
})
]
}
微应用与微应用之间
在应用加载时标记所有的 link 和 style 标签,卸载时同步移除:
// 加载时标记
function loadApp(appName) {
const styles = document.querySelectorAll('link, style');
styles.forEach(style => {
style.setAttribute('data-app', appName);
});
}
// 卸载时清理
function unloadApp(appName) {
const styles = document.querySelectorAll(`[data-app="${appName}"]`);
styles.forEach(style => style.remove());
}
JavaScript 隔离
微应用的 JavaScript 运行时会修改全局对象 window,例如 jQuery 会挂载 window.$,React、Vue 也会有类似行为。
沙箱机制(SandBox)
沙箱让局部 JavaScript 对外部对象的访问和修改处在可控范围内,确保内部运行不影响外部对象。
浏览器端实现需要结合 with 关键字和 Proxy 对象:
class SandBox {
constructor() {
this.proxy = null;
this.running = false;
}
active() {
this.running = true;
const fakeWindow = Object.create(null);
this.proxy = new Proxy(fakeWindow, {
get(target, prop) {
return prop in target ? target[prop] : window[prop];
},
set(target, prop, value) {
target[prop] = value;
return true;
}
});
}
inactive() {
this.running = false;
}
}
// 使用
const sandbox = new SandBox();
sandbox.active();
// 在 sandbox.proxy 环境中执行微应用代码
sandbox.inactive();
关键点
- CSS 隔离可通过命名空间或 CSS Module 实现,打包时自动添加前缀
- 微应用卸载时需同步清理其注入的样式标签
- JavaScript 隔离采用沙箱机制,使用 Proxy 拦截对全局对象的访问
- 沙箱确保微应用的全局变量修改不会影响主应用和其他微应用
目录