认识
一、认识
二、路由同步
子应用注册的时候,提供子应用激活规则 (路由字符串 或 函数)。因此,监听 hashchange
和 popstate
事件,在事件回调函数中,根据注册的子应用激活规则,卸载/激活子应用。
以 Vue-Router
的 history
模式为例,在切换路由时,通常会做三件重要事情:执行一连串的 hook
函数、更新url
、router-view
更新,其中更新 url
,就是通过 pushState/replaceState
的形式实现的。因此重写并增强 history.pushState
和 history.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"
);
以上主要是增加了hashchange
、popstate
两个监听,监听url
的变化。同时重写pushState
以及replaceState
方法,在方法中调用原有方法后执行如何处理子应用的逻辑监听hashchange
及popstate
事件,事件触发后执行如何处理子应用的逻辑。
三、生命周期
single-spa
的一个关键点就是生命周期,子应用生命周期包含bootstrap
,mount
,unmount
三个回调函数。主应用在管理子应用的时候,通过子应用暴露的生命周期函数来实现子应用的启动和卸载。
-
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
使用JS
写CSS
,也是目前比较主流的方案,完全不需要些单独的 css
文件,所有的 css
代码全部放在组件内部,以实现 css
的模块化,但对于历史代码不好处理