配置 single-spa
The single-spa root config consists of the following:
这两个根目录下的配置用于启动single-spa应用。
- 所有微前端应用共享的根 HTML 页面
- 调用 singleSpa.registerApplication() 的 JavaScript
Index.html文件
内容可参考该示例。注意该文件不包含html元素(div, buttons等),只是为了调用registerApplication()
方法。
See this example root config for what a root HTML file looks like.
在使用single-spa时,不必使用SystemJS,不过为了能够独立部署各应用,很多示例和教程会推荐使用SystemJS。
注册应用
你需要先注册应用,这样single-spa才知道在什么时机,如何去初始化、下载、挂载和卸载各应用。我们一般情况下在single-spa的配置文件中进行注册,当然也可以有其他方式(不推荐)。如果在某个应用中注册其他应用,这两个应用不会存在嵌套关系,他们还是同级关系,应用的挂载和下载也还是会依赖各自的触发条件(activity functions)。
我们通过调用registerApplication
方法来注册应用。例如:
// single-spa-config.js
import { registerApplication, start } from 'single-spa';
// Simple usage
registerApplication(
'app2',
() => import('src/app2/main.js'),
(location) => location.pathname.startsWith('/app2'),
{ some: 'value' }
);
// Config with more expressive API
registerApplication({
name: 'app1',
app: () => import('src/app1/main.js'),
activeWhen: '/app1',
customProps: {
some: 'value',
}
);
start();
参数
name
registerApplication
的第一个参数表示应用名称,name
必须是string类型
Loading Function or Application
registerApplication
的第二个参数可以是一个Promise类型的 加载函数,也可以是一个已经被解析的应用。
Application as second argument
你可以选择将一个已经被解析过的应用作为registerApplication
的第二个参数,这个应用其实是一个包含各个生命周期函数的对象。我们既可以从另外一个文件中引入该对象,也可以在single-spa的配置文件中定义这个对象。
const application = {
bootstrap: () => Promise.resolve(), //bootstrap function
mount: () => Promise.resolve(), //mount function
unmount: () => Promise.resolve(), //unmount function
}
registerApplication('applicationName', application, activityFunction)
加载函数
registerApplication
的第二个参数必须是返回promise的函数(或"async function"方法)。这个函数没有入参,会在应用第一次被下载时调用。返回的Promise resolve之后的结果必须是一个可以被解析的应用。常见的实现方法是使用import加载:() => import('/path/to/application.js')
激活函数
registerApplication
的第三个参数需要是一个纯函数,window.location
会作为第一个参数被调用,当函数返回的值为真(truthy)值时,应用会被激活。通常情况下,Activity function会根据window.location
/后面的path来决定该应用是否需要被激活。
另外一种场景是single-spa根据顶级路由查找应用,而每个应用会处理自身的子路由。 在以下场景,single-spa会调用应用的activity function
在以下情况下,single-spa将调用每个应用的活动函数:
hashchange
orpopstate
事件触发时pushState
orreplaceState
被调用时- 在single-spa上手动调用[
triggerAppChange
] 方法 checkActivityFunctions
方法被调用时
自定义属性
registerApplication
函数可选的第四个参数是 custom props。这个参数会传递给 single-spa 的 lifecycle
函数。自定义属性可以是一个对象,也可以是一个返回Object的函数。如果自定属性是一个函数,函数的参数是应用的名字(application name)和当前window.location
。
使用对象参数
singleSpa.registerApplication({
name: 'myApp',
app: () => import('src/myApp/main.js'),
activeWhen: ['/myApp', (location) => location.pathname.startsWith('/some/other/path')],
customProps: {
some: 'value',
},
});
singleSpa.registerApplication({
name: 'myApp',
app: () => import('src/myApp/main.js'),
activeWhen: ['/myApp', (location) => location.pathname.startsWith('/some/other/path')],
customProps: (name, location) => ({
some: 'value',
}),
});
config.name
必须是字符串。
config.app
应用的定义,它可以是一个单spa生命周期的对象,加载函数或者与第二个参数相同。
config.activeWhen
可以是激活函数,比如参数API、路径前缀或两者的数组。因为最常见的用例是使用window.location
将其URL前缀进行匹配,所以我们帮你实现了这个方法。
Path prefix
路径前缀会匹配url,允许以下每一种前缀:
- '/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
config.customProps
The optional customProps
property provides custom props that are passed to the application's single-spa lifecycle functions. The custom props may be either an object or a function that returns an object. Custom prop functions are called with the application name and current window.location
as arguments.
Calling singleSpa.start()
start()方法
必须被single-spa配置文件的js调用,这时应用才会被真正挂载。在start
被调用之前,应用先被下载,但不会初始化/挂载/卸载。start
方法可以协助我们更好提升应用的性能。举个例子,我们可能会马上注册一个应用(为了立刻下载代码),但不能马上就在DOM节点上挂载该应用,而是需要等一个AJAX请求(可能会获取用户的登录信息)完成后,再根据结果进行挂载。这种情况下,最佳实践是先调用registerApplication
,等AJAX请求完成后再调用start
。
//single-spa-config.js
import { start } from 'single-spa';
/*在注册应用之前调用start意味着single-spa可以立即安装应用,无需等待单页应用的任何初始设置。*/
start();
// 注册应用。。。。
同时注册两个路由??
emm...也是可以的。 如果你能用正确的方式来实现,这件事并不可怕。一旦你正确实现了,这将非常非常厉害。一种实现方式是为每个app创建一个<div id="app name"></div>
,这样这两个应用就不会同时修改相同的DOM节点了。[考虑一个path变动,同时有两个应用被激活的场景,译者注]
<div>
需要一个id
,这个id
的以single-spa-application
前缀开头,后面接着你的应用的名字。比如,如果你的应用名字叫做app-name
,就创建一个id为 single-spa-application:app-name
的div
。
一个多应用的的例子看着就像这样:
<div id="single-spa-application:app-name"></div>
<div id="single-spa-application:other-app"></div>