跳到主要内容

认识

2023年07月21日
柏拉文
越努力,越幸运

一、认识


二、路由同步


子应用注册的时候,提供子应用激活规则 (路由字符串 或 函数)。因此,监听 hashchangepopstate 事件,在事件回调函数中,根据注册的子应用激活规则,卸载/激活子应用。

Vue-Routerhistory 模式为例,在切换路由时,通常会做三件重要事情:执行一连串的 hook 函数、更新urlrouter-view 更新,其中更新 url,就是通过 pushState/replaceState 的形式实现的。因此重写并增强 history.pushStatehistory.replaceState 方法,在执行它们的时候,可以拿到执行前、执行后的 url,对比是否有变化,如果有,根据注册的子应用激活规则,卸载/激活子应用。

// We will trigger an app change for any routing events.
window.addEventListener("hashchange", urlReroute);
window.addEventListener("popstate", urlReroute);

// Monkeypatch addEventListener so that we can ensure correct timing
const originalAddEventListener = window.addEventListener;
const originalRemoveEventListener = window.removeEventListener;
window.addEventListener = function (eventName, fn) {
if (typeof fn === "function") {
if (
routingEventsListeningTo.indexOf(eventName) >= 0 &&
!find(capturedEventListeners[eventName], (listener) => listener === fn)
) {
capturedEventListeners[eventName].push(fn);
return;
}
}

return originalAddEventListener.apply(this, arguments);
};

window.removeEventListener = function (eventName, listenerFn) {
if (typeof listenerFn === "function") {
if (routingEventsListeningTo.indexOf(eventName) >= 0) {
capturedEventListeners[eventName] = capturedEventListeners[
eventName
].filter((fn) => fn !== listenerFn);
return;
}
}

return originalRemoveEventListener.apply(this, arguments);
};

window.history.pushState = patchedUpdateState(
window.history.pushState,
"pushState"
);
window.history.replaceState = patchedUpdateState(
window.history.replaceState,
"replaceState"
);

以上主要是增加了hashchangepopstate两个监听,监听url的变化。同时重写pushState以及replaceState方法,在方法中调用原有方法后执行如何处理子应用的逻辑监听hashchangepopstate事件,事件触发后执行如何处理子应用的逻辑。

三、生命周期


single-spa的一个关键点就是生命周期,子应用生命周期包含bootstrapmountunmount三个回调函数。主应用在管理子应用的时候,通过子应用暴露的生命周期函数来实现子应用的启动和卸载。

Preview
  • load: 当应用匹配路由时就会加载脚本(非函数,只是一种状态)。

  • bootstrap: 应用内容首次挂载到页面前调用。

  • Mount: 当主应用判定需要激活这个子应用时会调用, 实现子应用的挂载、页面渲染等逻辑。

  • unmount: 当主应用判定需要卸载这个子应用时会调用, 实现组件卸载、清理事件监听等逻辑。

  • unload: 非必要函数,一般不使用。unload之后会重新启动bootstrap流程。

四、JS隔离


JS 隔离的核心是在基座和子应用中使用不同的上下文 (global env),从而达成基座和子应用之间 js 运行互不影响。简单来说,就是给子应用单独的 window,避免对基座的 window 造成污染。

五、样式隔离


5.1 shadowDOM

5.2 Css Modules

CSS Modules 代码中的每一个类名都是引入对象的一个属性,通过这种方式,即可在使用时明确指定所引用的 css 样式。并且 CSS Modules 在打包的时候会自动将类名转换成 hash 值,完全杜绝 css 类名冲突的问题;

5.3 Css In Js

使用JSCSS,也是目前比较主流的方案,完全不需要些单独的 css 文件,所有的 css 代码全部放在组件内部,以实现 css 的模块化,但对于历史代码不好处理