Single-SPA Application API
import { registerApplication, start } from "single-spa"
// or
import * as singleSpa from "single-spa"
registerApplication
使用在 root config 中,用于注册应用
Simple arguments
singleSpa.registerApplication(
"app-name",
() => System.import("appName"),
(location) => location.pathname.startsWith("app")
)
Arguments - appName: string 应用的名称 - applicationOrLoadingFn:() => <Function | Promise> 一个返回应用或 Promise 的函数 - activeFn: (location) => boolean 纯函数,以 window.location 为参数,返回 true 表示激活该应用,false 表示卸载该应用 - customProps?: Object | () => Object 可选,需要传递给应用生命周期钩子的自定义参数 |
Configuration Object
singleSpa.registerApplication({
name: "app-name",
app: () => System.import("appName"),
activeWhen: "/app",
customProps: {
authToken: "xxxxx",
},
})
Arguments - name: string 应用的名称 - app: Application | () => Application | Promise |
(location) => boolean | (string | (location) => boolean)[] 什么时候激活应用与上面的一样 - customProps?: Object | () => Object 可选,需要传递给应用生命周期钩子的自定义参数 |
start
让 single-spa 对应用进行控制,让您可以控制单页应用程序的性能
singleSpa.start()
singleSpa.start({
urlRerouteOnly: true,
})
Arguments 一个可选的对象,这个对象有 urlRerouteOnly 属性 urlRerouteOnly:一个默认为 false 的布尔值。如果设置为 true,则除非更改了客户端路由,否则对 history.pushState()和 history.replaceState()的调用将不会触发单 spa 重新路由。在某些情况下,将此值设置为 true 可能会更好。
triggerAppChange
手动触发 single-spa 加载应用
singleSpa.triggerAppChange()
navigatToUrl
在已注册的应用之间执行 url 导航,而不需要处理 event.preventDefault() pushState triggerAppChange
// Three ways of using navigateToUrl
singleSpa.navigateToUrl("/new-url")
singleSpa.navigateToUrl(document.querySelector("a"))
document.querySelector("a").addEventListener(singleSpa.navigateToUrl)
Arguments navigationObj: string | context | DOMEvent - url 字符串 - 带有 href 属性的标签,例如 a 标签 - 一个具有 href 属性的 DOMElement 上的 click 事件的 DOMEvent 对象;
getMountedApps
获取挂载(MOUNTED)应用的名字,返回一个字符串数组
const mountedAppNames = singleSpa.getMountedApps()
console.log(mountedAppNames) // ['app1', 'app2', 'navbar']
getAppNames
获取所有注册的应用,与应用的状态无关
const appNames = singleSpa.getAppNames()
console.log(appNames) // ['app1', 'app2', 'app3', 'navbar']
getAppStatus
获取指定应用的状态
const status = singleSpa.getAppStatus("app1")
console.log(status) // one of many statuses (see list below). e.g. MOUNTED
Arguments appName: string 注册应用的名字
Returns appStatus: string | null , null 表示应用不存在 - NOT_LOADEDapp :应用已经注册,但是还没有加载好 - LOADING_SOURCE_CODE:已经获取到源代码 - NOT_BOOTSTRAPPED: 应用已经加载好,但是还没开始初始化 - BOOTSTRAPPING:已经调用 bootstrap 生命周期钩子,但是还没执行完 - NOT_MOUNTED:已经执行好 bootstrap ,但是还没挂载 - MOUNTING:正在执行 mount 钩子 - MOUNTED:应用已经挂载在 DOM 上了 - UNMOUNTING:正在执行 unmount - UNLOADING:正在执行 unloading - SKIP_BECAUSE_BROKEN:应用在加载,引导,安装或卸载期间引发了错误,并且由于行为不当而被跳过,因此已被隔离。其他应用将继续正常运行。 - LOAD_ERROR:应用在 loading 方法中返回了 reject 的 Promise,这通常是由于尝试下载应用程序的 JavaScript 软件包的网络错误。
unloadApplication
卸载已注册的应用程序的目的是将其设置回 NOT_LOADED 状态,这意味着它将在下次需要安装时重新引导。这样做的主要用例是允许热重载整个已注册的应用程序,但是无论何时您要重新引导应用程序,unloadApplication 都会很有用。
// Unload the application right now, without waiting for it to naturally unmount.
singleSpa.unloadApplication("app1")
// Unload the application only after it naturally unmounts due to a route change.
singleSpa.unloadApplication("app1", { waitForUnmount: true })
当调用 unloadApplication 后 Single-spa 会执行如下几步 1. 在要卸载的注册应用程序上调用卸载生命周期。 2. 设置 App 状态为 NOT_LOADED 3. 触发重新路由,在这期间 single-spa 会挂载刚卸载的应用 因为调用 unloadApplication 时可能会挂载已注册的应用程序,所以您可以指定是要立即卸载还是要等待直到不再挂载该应用程序。这是通过 waitForUnmount 选项完成的。
Arguments appName: string 应用名称 Options?: { waitForUnmoun: boolean = false} 可选对象参数,默认 single-spa 会立即卸载指定应用,如果设置为 true,single-spa 会等应用不处于 MOUNTED 状态的时候进行卸载。
unregisterApplication
unregisterApplication 函数将卸载,卸载和注销应用程序,一旦调用,应用不会再挂载
import { unregisterApplication } from "single-spa"
unregisterApplication("app1").then(() => {
console.log("app1 is now unmounted, unloaded, and no longer registered!")
})
- Unregistering 应用程序不会将其从SystemJS模块注册表中删除。
- Unregistering 应用程序不会从浏览器内存中删除其代码或javascript框架。
- Unregistering 应用程序的另一种方法是在应用程序的活动功能内执行权限检查。这具有防止应用程序挂载的类似效果。
Arguments appName: string 应用名称
checkActivityFunctions
将使用模拟窗口位置调用每个应用程序的活动函数,并提供应在该位置挂载哪些应用程序的列表。
const appsThatShouldBeActive = singleSpa.checkActivityFunctions()
console.log(appsThatShouldBeActive) // ['app1']
const appsForACertainRoute = singleSpa.checkActivityFunctions({
pathname: "/app2",
})
console.log(appsForACertainRoute) // ['app2']
Arguments mockWindowLocation: string 表示 window.location 的字符串,将在调用每个应用程序的活动函数以测试它们是否返回 true 时使用。
Returns appNames: string[] 返回符合的应用名称的数组
addErrorHandler
在生命周期函数或者激活函数中报错的时候会执行该方法,如果没有这个处理函数,就会直接抛出到窗口
singleSpa.addErrorHandler((err) => {
console.log(err)
console.log(err.appOrParcelName)
console.log(singleSpa.getAppStatus(err.appOrParcelName))
})
Arguments errorHandler: Function(error: Error) 将通过 Error 对象调用,该对象还具有 message 和 appOrParcelName 属性。
removeErrorHandler
移除错误处理函数
singleSpa.addErrorHandler(handleErr)
singleSpa.removeErrorHandler(handleErr)
function handleErr(err) {
console.log(err)
}
Arguments errorHandler: Function 函数名称
Returns Boolean :true 表示移除成功
mountRootParcel
创建并挂载一个 singel-spa parcel
// Synchronous mounting
const parcel = singleSpa.mountRootParcel(parcelConfig, {
prop1: "value1",
domElement: document.getElementById("a-div"),
})
parcel.mountPromise.then(() => {
console.log("finished mounting the parcel!")
})
// Asynchronous mounting. Feel free to use webpack code splits or SystemJS dynamic loading
const parcel2 = singleSpa.mountRootParcel(() => import("./some-parcel.js"), {
prop1: "value1",
domElement: document.getElementById("a-div"),
})
Arguments parcelConfig: object | loading Function parcelProps: object 具有 DOM 元素属性的对象
returns Parcel object
pathToActiveWhen
pathToActiveWhen 函数将字符串 URL 路径转换为活动函数。字符串路径可能包含 single-spa 匹配任何字符的路由参数。假定提供的字符串是前缀。
当在注册应用的时候给 ativeWhen 传递一个字符串时会被调用 Arguments Path: string url 的前缀 returns: (location: location) => boolean Examples
let activeWhen = singleSpa.pathToActiveWhen("/settings")
activewhen(new URL("http://localhost/settings")) // true
activewhen(new URL("http://localhost/settings/password")) // true
activeWhen(new URL("http://localhost/")) // false
activeWhen = singleSpa.pathToActiveWhen("/users/:id/settings")
activewhen(new URL("http://localhost/users/6f7dsdf8g9df8g9dfg/settings")) // true
activewhen(new URL("http://localhost/users/1324/settings")) // true
activewhen(new URL("http://localhost/users/1324/settings/password")) // true
activewhen(new URL("http://localhost/users/1/settings")) // true
activewhen(new URL("http://localhost/users/1")) // false
activewhen(new URL("http://localhost/settings")) // false
activeWhen(new URL("http://localhost/")) // false
activeWhen = singleSpa.pathToActiveWhen("/page#/hash")
activeWhen(new URL("http://localhost/page#/hash")) // true
activeWhen(new URL("http://localhost/#/hash")) // false
activeWhen(new URL("http://localhost/page")) // false
ensureJQuerySupport
用于保障不同版本的 jQuery 的 event delegation
Arguments jQuery? : JQueryFn = window.jQuery 对 jQuery 已绑定到的全局变量的引用
setBootstrapMaxTime
设置全局 bootstrap 的超时时间
// After three seconds, show a console warning while continuing to wait.
singleSpa.setBootstrapMaxTime(3000)
// After three seconds, move the application to SKIP_BECAUSE_BROKEN status.
singleSpa.setBootstrapMaxTime(3000, true)
// don't do a console warning for slow lifecycles until 10 seconds have elapsed
singleSpa.setBootstrapMaxTime(3000, true, 10000)
Arguments Mills: number 超时之前等待 bootstrap 完成的毫秒数。 dieOnTimeout: boolean = false 如果为 false,则已注册的应用程序会使速度降低,直到达到 mills 之前,只会在控制台中引起一些警告。如果为 true,则使已注册应用程序将被置为 SKIP_BECAUSE_BROKEN 状态,在此状态下,它们将再也没有机会改变内容。 warningMillis: number = 1000 在最终超时之前发生的控制台警告之间等待的毫秒数。
setMountMaxTime
设置全局 mount 的超时时间
// After three seconds, show a console warning while continuing to wait.
singleSpa.setMountMaxTime(3000)
// After three seconds, move the application to SKIP_BECAUSE_BROKEN status.
singleSpa.setMountMaxTime(3000, true)
// don't do a console warning for slow lifecycles until 10 seconds have elapsed
singleSpa.setMountMaxTime(3000, true, 10000)
Arguments 同上
setUnmountMaxTime
设置全局 unmount 的超时时间
// After three seconds, show a console warning while continuing to wait.
singleSpa.setUnmountMaxTime(3000)
// After three seconds, move the application to SKIP_BECAUSE_BROKEN status.
singleSpa.setUnmountMaxTime(3000, true)
// don't do a console warning for slow lifecycles until 10 seconds have elapsed
singleSpa.setUnmountMaxTime(3000, true, 10000)
Arguments 同上
setUnloadMaxTime
设置 unload 的超时时间
// After three seconds, show a console warning while continuing to wait.
singleSpa.setUnloadMaxTime(3000)
// After three seconds, move the application to SKIP_BECAUSE_BROKEN status.
singleSpa.setUnloadMaxTime(3000, true)
// don't do a console warning for slow lifecycles until 10 seconds have elapsed
singleSpa.setUnloadMaxTime(3000, true, 10000)
Arguments 同上
Event
single-spa 将事件触发到窗口,作为您的代码挂接到 URL 过渡的一种方式
PopStateEvent
当 single-spa 想要所有激活的应用重新渲染时,通过该事件触发。当一个应用程序调用 history.pushState,history.replaceState 或 triggerAppChange 时,就会发生这种情况。
window.addEventListener("popstate", (evt) => {
if (evt.singleSpa) {
console.log(
"This event was fired by single-spa to forcibly trigger a re-render"
)
console.log(evt.singleSpaTrigger) // pushState | replaceState
} else {
console.log("This event was fired by native browser behavior")
}
})
Canceling navigation
取消导航是指更改 URL,然后立即将其更改回之前的状态。这个发生在 mounting 、unmounting 或者 loading 之前完成。可以与 Vue 路由器和 Angular 路由器的内置导航保护功能结合使用,这些功能可以取消导航事件。
// 监听 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()
}
}
)
Custom Events
每当重新路由时,single-spa 都会触发一系列自定义事件。每当浏览器 URL 发生任何更改或调用 triggerAppChange 时,都会发生重新路由
window.addEventListener("single-spa:before-routing-event", (evt) => {
const {
originalEvent,
newAppStatuses,
appsByNewStatus,
totalAppChanges,
oldUrl,
newUrl,
navigationIsCanceled,
cancelNavigation,
} = evt.detail
console.log(
"original event that triggered this single-spa event",
originalEvent
) // PopStateEvent | HashChangeEvent | undefined
console.log(
"the new status for all applications after the reroute finishes",
newAppStatuses
) // { app1: MOUNTED, app2: NOT_MOUNTED }
console.log(
"the applications that changed, grouped by their status",
appsByNewStatus
) // { MOUNTED: ['app1'], NOT_MOUNTED: ['app2'] }
console.log(
"number of applications that changed status so far during this reroute",
totalAppChanges
) // 2
console.log("the URL before the navigationEvent", oldUrl) // http://localhost:8080/old-route
console.log("the URL after the navigationEvent", newUrl) // http://localhost:8080/new-route
console.log("has the navigation been canceled", navigationIsCanceled) // false
// The cancelNavigation function is only defined in the before-routing-event
evt.detail.cancelNavigation()
})
before-app-change event
当至少一个应用程序更改状态,在重新路由之前会触发 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
})
before-no-app-change
当零个应用程序更改状态,在重新路由之前会触发 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
})
before-routing-event
在每个路由事件发生之前(即在每个 hashchange,popstate 或 triggerAppChange 之后)都会触发 single-spa:before-routing-event 事件,即使不需要更改已注册的应用程序也是如此。
window.addEventListener("single-spa:before-routing-event", (evt) => {
console.log("single-spa is about to mount/unmount applications!")
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
})
before-mount-routing-event
在 routing-event 之前,在 before-routing-event 之后,保证在所有应用 unmounted 之后,所有新应用 mounted 之前触发
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
})
before-first-mount
在任何一个应用第一次挂载之前触发,因此只触发一次,这在应用已经加载好但是还没 mounting 之后。
window.addEventListener("single-spa:before-first-mount", () => {
console.log(
"single-spa is about to mount the very first application for the first time"
)
})
first-mount
在任何一个应用第一次挂载之前触发,因此只触发一次
window.addEventListener("single-spa:first-mount", () => {
console.log("single-spa just mounted the very first application")
})
app-change event
至少一个应用 loaded、bootstrap、mounted、unmounted 或者 unloaded 触发,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
})
no-app-change event
当没有应用 loaded、boostrapped 、mounted、unmounted 或者 unloaded 时触发。每个路由事件只会触发一个。
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
})
routing-event
每次发生路由事件时(在每个 hashchange,popstate 或 triggerAppChange 之后),都 会触发 single-spa:routing-event 事件,即使无需更改已注册的应用程序;之后 single-spa 会验证所有应用正确 loaded、bootstrapped、mounted、unmounted
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
})