Applications API
single-spa输出的是命名函数和变量而不是默认输出,这意味着引用必须用以下两种方式:
import { registerApplication, start } from 'single-spa';
// or
import * as singleSpa from 'single-spa';
registerApplication
registerApplication
是基础配置会用到的最重要的API,调用这个方法可以在single-spa中注册一个应用。
请注意,如果一个应用是从另一个应用中注册的,则不会在在多个应用之间维护层次结构。
有两种方法注册应用:
简单参数
singleSpa.registerApplication(
'appName',
() => System.import('appName'),
location => location.pathname.startsWith('appName')
)
参数
- appName: string
- 应用的名字将会在single-spa中注册和引用, 并在开发工具中标记。
- applicationOrLoadingFn: () => <Function | Promise>
- 必须是一个加载函数,返回一个应用或者一个Promise。
- activityFn: (location) => boolean
- 必须是个纯函数, 该函数由
window.location
作为第一个参数被调用, 当应用应该被激活时它应该返回一个真值。 - customProps?: Object =
- 在生命周期钩子函数执行时会被作为参数传入
returns
undefined
对象参数
singleSpa.registerApplication({
name: 'appName',
app: () => System.import('appName'),
activeWhen: '/appName'
customProps: {}
})
参数
- name: string
- 应用的名字将会在single-spa中注册和引用, 并在开发工具中标记。
- app: Application | () => Application | Promise<Application>
- 可以是应用的实例对象,也可是返回应用的实例对象的函数(Promise或者普通函数都可以)。
- activeWhen: string | (location) => boolean | (string | (location) => boolean)[]
- 可以是一个路径前缀,它将匹配每个以该路径开头的URL,也可以是激活函数(如简单参数中所述)或一个数组两者都包含在内。如果任何条件为真,则保留应用活动。路径前缀也接受动态值(以':'开头),因为有些路径会接收url参数,但仍然应该激活您的应用。 Examples:
- '/app1'
- ✅ https://app.com/app1
- ✅ https://app.com/app1/anything/everything
- 🚫 https://app.com/app2
- '/users/:userId/profile'
- ✅ https://app.com/users/123/profile
- ✅ https://app.com/users/123/profile/sub-profile/
- 🚫 https://app.com/users//profile/sub-profile/
- 🚫 https://app.com/users/profile/sub-profile/
- '/pathname/#/hash'
- ✅ https://app.com/pathname/#/hash
- ✅ https://app.com/pathname/#/hash/route/nested
- 🚫 https://app.com/pathname#/hash/route/nested
- 🚫 https://app.com/pathname#/another-hash
- ['/pathname/#/hash', '/app1']
- ✅ https://app.com/pathname/#/hash/route/nested
- ✅ https://app.com/app1/anything/everything
- 🚫 https://app.com/pathname/app1
- 🚫 https://app.com/app2
- customProps?: Object = {}
- 在生命周期钩子函数执行时会被作为参数传入
returns
undefined
详细解析请见 Configuration docs
start
singleSpa.start();
// Optionally, you can provide configuration
singleSpa.start({
urlRerouteOnly: true
});
必须在你single spa的配置中调用!在调用 start
之前, 应用会被加载, 但不会初始化,挂载或卸载。 start
的原因是让你更好的控制你单页应用的性能。举个栗子,你想立即声明已经注册过的应用(开始下载那些激活应用的代码),但是实际上直到初始化AJAX(或许去获取用户的登录信息)请求完成之前不会挂载它们 。 在这个例子里,立马调用 registerApplication
方法,完成AJAX后再去调用 start
方法会获得最佳性能。
arguments
The start(opts)
api optionally accepts a single opts
object, with the following properties. If the opts object is omitted, all defaults will be applied.
urlRerouteOnly
: A boolean that defaults to false. If set to true, calls tohistory.pushState()
andhistory.replaceState()
will not trigger a single-spa reroute unless the client side route was changed. Setting this to true can be better for performance in some situations. For more information, read original issue.
returns
undefined
triggerAppChange
singleSpa.triggerAppChange();
返回一个Promise对象,当所有应用挂载/卸载时它执行 resolve/reject 方法,它一般被用来测试single-spa,在生产环境可能不需要。
arguments
none
returns
- Promise
- 返回一个Promise对象,当所有应用挂载/卸载时它执行 resolve/reject 方法。
navigateToUrl
// Three ways of using navigateToUrl
singleSpa.navigateToUrl("/new-url");
singleSpa.navigateToUrl(document.querySelector('a'));
document.querySelector('a').addEventListener(singleSpa.navigateToUrl);
<!-- A fourth way to use navigateToUrl, this one inside of your HTML -->
<a href="/new-url" onclick="singleSpaNavigate()">My link</a>
使用这个通用方法来轻松的实现在不同注册应用之前的切换,而不必需要处理 event.preventDefault()
, pushState
, triggerAppChange()
等待。
arguments
- navigationObj: string | context | DOMEvent
- navigationObj 必须是一下类型中的一个:
- 一个 url 字符串
- 一个 上下文 / 参数为
href
属性; 在调用singleSpaNavigate.call(anchorElement)
时很有用,一个指向其他原色的锚点,或者其他内容。 - 一个 DOMEvent对象,具有
href
attribute; 方便<a onclick="singleSpaNavigate"></a>
方法调用。
returns
undefined
getMountedApps
const mountedAppNames = singleSpa.getMountedApps();
console.log(mountedAppNames); // ['app1', 'app2', 'navbar']
arguments
none
returns
- appNames: string[]
- 当前已经挂载应用的名字。
MOUNTED
getAppNames
const appNames = singleSpa.getAppNames();
console.log(appNames); // ['app1', 'app2', 'app3', 'navbar']
arguments
none
returns
- appNames: string[]
- 当前应用的名字(任何状态的应用)。
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_LOADED
- single-spa应用注册了,还未加载。
- LOADING_SOURCE_CODE
- 应用代码正在被拉取。
- NOT_BOOTSTRAPPED
- 应用已经加载,还未初始化。
- BOOTSTRAPPING
bootstrap
的生命周期函数已经执行,还未结束。- NOT_MOUNTED
- 应用已经加载和初始化,还未挂载。
- MOUNTING
- 应用正在被挂载,还未结束。
- MOUNTED
- 应用目前处于激活状态,已经挂载到DOM元素上。
- UNMOUNTING
- 应用正在被卸载,还未结束。
- UNLOADING
- 应用正在被移除,还未结束。
- SKIP_BECAUSE_BROKEN
- 应用在加载、初始化、挂载或卸载过程中抛出错误,由于行为不当而被跳过,因此被隔离。其他应用将正常运行。
- LOAD_ERROR
- 应用的加载功能返回了一个rejected的Promise。这通常是由于下载应用程序的javascript包时出现网络错误造成的。Single-spa将在用户从当前路由导航并返回后重试加载应用。
注意 LOAD_ERROR 的状态
请注意,如果使用SystemJS加载包,则需要添加以下代码,以使SystemJS在加载函数调用 LOAD_ERROR
状态下的应用程序上的 System.import()
时重新尝试网络请求。
singleSpa.addErrorHandler(err => {
if (singleSpa.getAppStatus(err.appOrParcelName) === singleSpa.LOAD_ERROR) {
System.delete(System.resolve(err.appOrParcelName));
}
})
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});
移除已注册的应用的目的是将其设置回 NOT_LOADED
状态,这意味着它将在下一次需要挂载时重新初始化。它的主要使用场景是允许热加载所有已注册的应用,但是 unloadApplication
可以在您希望初始化应用时非常有用。
当调用 unloadApplication
时,Single-spa执行以下步骤。
- 在一个已经注册的应用上,调用 unload lifecyle 方法。
- 将次应用的状态置为 NOT_LOADED
- 触发路由重定向,在此期间single-spa可能会挂载刚刚卸载的应用程序。
因为在调用 unloadApplication
时可能会挂载已注册的应用,所以可以指定是要立即卸载还是要等到应用不再挂载。这是通过 waitForUnmount
参数完成的。
arguments
- appName: string
- 注册应用的名字
- options?: {waitForUnmount: boolean = false}
- 参数必是一个包含
waitForUnmount
属性的对象。当 `waitForUnmount` 是 `false`, single-spa 立刻移除特定应用,尽管它已经被挂载。 当它是true
时, single-spa 会等待到它的状态不再是MOUNTED
时才移除应用
returns
- Promise
- 当应用被成功移除时,Promise对象会被resolved。
checkActivityFunctions
const appsThatShouldBeActive = singleSpa.checkActivityFunctions();
console.log(appsThatShouldBeActive); // ['app1']
const appsForACertainRoute = singleSpa.checkActivityFunctions({pathname: '/app2'});
console.log(appsForACertainRoute); // ['app2']
将会调用每个应用的 mockWindowLocation
并且返回一个根据当前路判断那些应用应该被挂载的列表。
arguments
- mockWindowLocation: string
- 一个代表当前路径的字符串,当执行每个应用的激活函数时会用它来判断是否应该返回真。
returns
- appNames: string[]
- 每个满足当前路径
mockWindowLocation
应该激活的应用名称。
addErrorHandler
singleSpa.addErrorHandler(err => {
console.log(err);
console.log(err.appOrParcelName);
console.log(singleSpa.getAppStatus(err.appOrParcelName));
});
添加处理程序,该处理程序将在应用在生命周期函数或激活函数期间每次抛出错误时调用。当没有错误处理程序时,single-spa将错误抛出到窗口。
- errorHandler: Function(error: Error)
- 必须是一个函数。将会以 Error object
message
和appOrParcelName
为参数调用.
returns
undefined
removeErrorHandler
singleSpa.addErrorHandler(handleErr)
singleSpa.removeErrorHandler(handleErr)
function handleErr(err) {
console.log(err)
}
删除给定的错误处理程序函数。
arguments
- errorHandler: Function
- 引用错误处理函数。
returns
- boolean
- 当错误处理函数呗移除则为
true
否则false
mountRootParcel
// 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')});
将会创建并挂载一个 single-spa parcel.
注意:Parcel不会自动卸载。卸载需要手动触发。
arguments
- parcelConfig: Object or Loading Function
- [parcelConfig](/docs/parcels-api#parcel-configuration)
- parcelProps: Object with a domElement property
- [parcelProps](/docs/parcels-api#parcel-props)
returns
- Parcel object
- 详细信息请见 Parcels API 。
pathToActiveWhen
The pathToActiveWhen
function converts a string URL path into an activity function. The string path may contain route parameters that single-spa will match any characters to. It assumes that the string provided is a prefix.
This function is used by single-spa when a string is passed into registerApplication
as the activeWhen
argument.
Arguments
path
(string): The URL prefix that.
Return Value
(location: Location) => boolean
A function that accepts a URL as an argument and returns a boolean indicating whether the path matches that URL.
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('/user/: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
singleSpa.ensureJQuerySupport(jQuery);
jQuery使用 event delegation 所以 single-spa 必须给每个jQuery版本一个patch。single-spa 会试着自动寻找 window.jQuery
或 window.$
。 如果页面中有多个版本的jQuery存在或jQuery被绑定到多个全局变量,请调用这个的方法。
arguments
- jQuery?: JQueryFn = window.jQuery
- 对jQuery已绑定到的全局变量的引用。
returns
undefined
setBootstrapMaxTime
// 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
- millis: number
- 一个判断等待初始化是否超时的毫秒数。
- dieOnTimeout: boolean = false
如果设置为false,注册的应用运行变缓,在到达
millis
之前,只会在控制台中引起一些警告。如果设置为true, 注册的应用程序运行变缓,它们将被塞进一个skip_break_status,因为它们不会再打断程序。
每个已注册的应用程序都可以覆盖自己的此行为。
- warningMillis: number = 1000
- 一个判断等待控制台warning是否发生的毫秒数。
returns
undefined
setMountMaxTime
// 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
- millis: number
- 一个判断等待挂载是否超时的毫秒数。
- dieOnTimeout: boolean = false
如果设置为false,注册的应用运行变缓,在到达
millis
之前,只会在控制台中引起一些警告。如果设置为true, 注册的应用程序运行变缓,它们将被塞进一个skip_break_status,因为它们不会再打断程序。
每个已注册的应用程序都可以覆盖自己的此行为。
- warningMillis: number = 1000
- 一个判断等待控制台warning是否发生的毫秒数。
returns
undefined
setUnmountMaxTime
// 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
- millis: number
- 一个判断等待卸载是否超时的毫秒数。
- dieOnTimeout: boolean = false
如果设置为false,注册的应用运行变缓,在到达
millis
之前,只会在控制台中引起一些警告。如果设置为true, 注册的应用程序运行变缓,它们将被塞进一个skip_break_status,因为它们不会再打断程序。
每个已注册的应用程序都可以覆盖自己的此行为。
- warningMillis: number = 1000
- 一个判断等待控制台warning是否发生的毫秒数。
returns
undefined
setUnloadMaxTime
// 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
- millis: number
- 一个判断等待移除是否超时的毫秒数。
- dieOnTimeout: boolean = false
如果设置为false,注册的应用运行变缓,在到达
millis
之前,只会在控制台中引起一些警告。如果设置为true, 注册的应用程序运行变缓,它们将被塞进一个skip_break_status,因为它们不会再打断程序。
每个已注册的应用程序都可以覆盖自己的此行为。
- warningMillis: number = 1000
- 一个判断等待控制台warning是否发生的毫秒数。
returns
undefined
Events
single-spa fires Events to the window
as a way for your code to hook into URL transitions.
PopStateEvent
single-spa fires PopStateEvent events when it wants to instruct all active applications to re-render. This occurs when one application calls history.pushState, history.replaceState, or triggerAppChange. Single-spa deviates from the browser's default behavior in some cases, as described in this Github issue.
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')
}
});
Custom Events
single-spa fires a series of custom events whenever it reroutes. A reroute occurs whenever the browser URL changes in any way or a triggerAppChange
is called. The custom events are fired to the window
. Each custom event has a detail
property with the following properties:
window.addEventListener('single-spa:before-routing-event', evt => {
const { originalEvent, newAppStatuses, appsByNewStatus, totalAppChanges } = 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
})
The following table shows the order in which the custom events are fired during a reroute:
Event order | Event Name | Condition for firing |
---|---|---|
1 | single-spa:before-app-change or single-spa:before-no-app-change | Will any applications change status? |
2 | single-spa:before-routing-event | — |
3 | single-spa:before-mount-routing-event | — |
4 | single-spa:before-first-mount | Is this the first time any application is mounting? |
5 | single-spa:first-mount | Is this the first time any application was mounted? |
6 | single-spa:app-change or single-spa:no-app-change | Did any applications change status? |
7 | single-spa:routing-event | — |
before-app-change event
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
});
A single-spa:before-app-change
event is fired before reroutes that will result in at least one application changing status.
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
});
每次路由跳转后single-spa:routing-event
事件会被触发,它可能是 hashchange, popstate, 或者 triggerAppChange,甚至当前应用不需要修改时
; 在single-spa 校验所有app都正确加载,初始化,挂载,卸载之后此此事件触发。
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
});
每次加载,初始化,挂载,卸载或移除一个或多个应用程序时,都会触发 single-spa:app-change
事件。它与 single-spa:routing-event
路由事件类似,只是在一个或多个应用程序真正加载,初始化,挂载,卸载或移除之后,它才会启动。如果hashchange、popstate或triggerAppChange不会导致其中任何一个更改,则不会引发事件。
before-mount-routing-event
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
});
当没有加载,初始化,挂载,卸载或移除应用程序时,single-spa触发 single-spa:no-app-change
事件。这与 single-spa:app-change
事件正好相反。每个路由事件只会触发一个。
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');
});
在第一个single-spa应用被挂在之前,single-spa 会触发 single-spa:before-first-mount
事件;因此它只会触发一次。更具体点说,它只会在应用被加载但未挂载之前触发。
推荐用例: 在用户将要看到第一个应用挂载之前,移除一个loading。
first-mount
window.addEventListener('single-spa:first-mount', () => {
console.log('single-spa just mounted the very first application');
});
在第一个single-spa应用被挂在之后, single-spa 会触发 single-spa:first-mount
事件;因此它只会触发一次。
推荐用例: 输出用户看到应用之前花费了多长时间。