整体流程
初始化阶段
环境初始化
1、强化pushState和replaceState方法:由于调用history.pushState()或history.replaceState()不会触发popstate事件。所以需要改写。
2、收集和监听hashchange和popstate事件:触发应用加载,卸载等操作。
3、全局导出navigateToUrl:使用这个方法或自动判断应该刷新应用还是不刷新应用。
注册应用
1、处理应用参数的同时完善应用的相关参数,例如:初始化状态等
2、注册jQuery:使jQuery全局可用。
3、调用reroute。
校验阶段
运行阶段
调用start()之后:
加载阶段
1、加载应用资源更改状态
注:import()动态加载js,js又依赖其他js,这时候会等到全部加载完在执行下一步
启动阶段
1、在没有手动卸载资源或者刷新的前提下,只会调用一次声明周期:bootstrap
2、串行调用bootstrap的过程中,有时间调度检查。
挂载阶段
1、会多次触发生命周期:mount。
2、串行调用mount的过程中,有时间调度检查。
3、在没刷新的前提下,只会调用一次自定义事件:
- single-spa:before-first-mount
- single-spa:first-mount
卸载阶段
1、会多次触发生命周期:unmount。
2、串行调用mount的过程中,有时间调度检查。
应用整体生命周期调用场景
事件
1-1、single-spa:before-app-change:至少一个应用程序更改状态时触发。
window.addEventListener('single-spa:before-app-change', evt => {
console.log('single-spa is about to mount/unmount applications!');
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { app1: MOUNTED }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: ['app1'], NOT_MOUNTED: [] }
console.log(evt.detail.totalAppChanges); // 1
});
1-2、single-spa:before-no-app-change:无应用程序更改状态时触发。
window.addEventListener('single-spa:before-no-app-change', evt => {
console.log('single-spa is about to do a no-op reroute');
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: [], NOT_MOUNTED: [] }
console.log(evt.detail.totalAppChanges); // 0
});
2、single-spa:before-routing-event:一个 single-spa:before-routing-event 事件在每个路由事件发生之前被触发,这是在每个 hashchange、popstate 或 triggerAppChange 之后,即使不需要对注册的应用程序进行更改。要取消导航事件,请监听 single-spa: before-routing-event 事件。
window.addEventListener(
'single-spa:before-routing-event',
({ detail: { oldUrl, newUrl, cancelNavigation } }) => {
if (
new URL(oldUrl).pathname === '/route1' &&
new URL(newUrl).pathname === '/route2'
) {
cancelNavigation();
}
},
);
3、single-spa:before-mount-routing-event:它保证在卸载所有单spa 应用程序之后,但在安装任何新应用程序之前触发。
window.addEventListener('single-spa:before-mount-routing-event', evt => {
console.log('single-spa is about to mount/unmount applications!');
console.log(evt.detail);
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { app1: MOUNTED }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: ['app1'], NOT_MOUNTED: [] }
console.log(evt.detail.totalAppChanges); // 1
});
4、single-spa:before-first-mount:在安装第一个单spa 应用程序之前,单spa 会触发single-spa:before-first-mount 事件;因此它只会被发射一次。更具体地说,它在应用程序已经加载之后但在安装之前触发。推荐用法:在安装第一个应用程序之前,移除用户看到的加载条。
window.addEventListener('single-spa:before-first-mount', () => {
console.log(
'single-spa is about to mount the very first application for the first time',
);
});
5、single-spa:first-mount:在装入任何单个spa应用程序中的第一个后,单个spa将触发此事件;因此,它只能调用一次。推荐用法:记录用户看到安装的任何应用之前所用的时间。
window.addEventListener('single-spa:first-mount', () => {
console.log('single-spa just mounted the very first application');
});
6-1、single-spa:app-change:每次加载、引导、装载、卸载或卸载一个或多个应用时,都会触发一个spa:app change事件。它与single spa:routing事件类似,只是只有在一个或多个应用程序实际加载、引导、装载或卸载后才会触发。如果hashchange、popstate或triggerAppChange未导致这些更改之一,则不会触发事件。
window.addEventListener('single-spa:app-change', evt => {
console.log(
'A routing event occurred where at least one application was mounted/unmounted',
);
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { app1: MOUNTED, app2: NOT_MOUNTED }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: ['app1'], NOT_MOUNTED: ['app2'] }
console.log(evt.detail.totalAppChanges); // 2
});
6-2、single-spa:no-app-change:当没有加载、引导、装载、卸载或卸载任何应用程序时,single spa触发一个spa:no app change事件。这与单个spa:app更改事件相反。每个路由事件只触发一个。
window.addEventListener('single-spa:no-app-change', evt => {
console.log(
'A routing event occurred where zero applications were mounted/unmounted',
);
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: [], NOT_MOUNTED: [] }
console.log(evt.detail.totalAppChanges); // 0
});
7、single-spa:routing-event:每次发生路由事件时,即在每次hashchange、popstate或triggerAppChange之后触发事件,即使不需要更改已注册的应用程序;在单一spa验证所有应用程序都已正确加载、引导、装载和卸载之后。
window.addEventListener('single-spa:routing-event', evt => {
console.log('single-spa finished mounting/unmounting applications!');
console.log(evt.detail.originalEvent); // PopStateEvent
console.log(evt.detail.newAppStatuses); // { app1: MOUNTED, app2: NOT_MOUNTED }
console.log(evt.detail.appsByNewStatus); // { MOUNTED: ['app1'], NOT_MOUNTED: ['app2'] }
console.log(evt.detail.totalAppChanges); // 2
});
single-spa-react分析
bootstrap
根据参数,获取组件入口,同时可以获取到single-spa的参数。
if (opts.rootComponent) {
// This is a class or stateless function component
return Promise.resolve();
} else {
// They passed a promise that resolves with the react component. Wait for it to resolve before mounting
return opts.loadRootComponent(props).then((resolvedComponent) => {
opts.rootComponent = resolvedComponent;
});
}
mount
unmount
调用卸载代码
if (root && root.unmount) {
// React >= 18
const unmountResult = root.unmount();
} else {
// React < 18
opts.ReactDOM.unmountComponentAtNode(opts.domElements[props.name]);
}