A link to the
This paper is a recent analysis of single-SPA, and all the articles are as follows:
- An in-depth analysis of single-SPA — navigation events and Reroute
- In-depth analysis of Single-SPA — Startup and application management
- An in-depth look at single-SPA — the event mechanism
- Additional in-depth analysis of module mechanisms, life cycles, and microfront-end types is ongoing
Application is an important part of single-SPA. When running single-SPA, it involves registering/unregistering and uninstalling the Application. This article will provide an in-depth analysis of the startup of single-SPA itself and the management of applications within it.
Single – start of spa
Let’s start with an example of single-SPA code:
// 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();Copy the code
Among them, we can see:
-
Single-spa exports both registerApplication and start methods
-
Start is used to start the single-SPA application. Before that, we can also register the micro front end application with the registerApplication,
-
RegisterApplication is used to register the microfront-end application in single-SPA so that single-SPA knows when/how to initialize, load, and unload the application
start
The code for the start section of single-SPA is as follows:
export function start(opts) {
started = true;
if (opts && opts.urlRerouteOnly) {
setUrlRerouteOnly(opts.urlRerouteOnly);
}
if(isInBrowser) { reroute(); }}Copy the code
Here we can see:
start
Accept an OPTS object as a parameter, where the only configuration item is urlReouteOnly; If urlReouteOnly is set to true, thenhistory.pushState()
和history.replaceState()
Will not triggerreroute
- If in a browser environment, call
start
Would triggerreroute
The implementation of the
Application management
The management of micro-front-end applications in single-SPA mainly involves:
- After you register an application, you can configure the application name and activation time
- If an application is unregistered, the corresponding application will be unregistered
Application registerApplication
Execute the process
To use the registerApplication, we can look directly at the code:
export function registerApplication(appNameOrConfig, appOrLoadApp, activeWhen, customProps) {
const registration = sanitizeArguments(
appNameOrConfig,
appOrLoadApp,
activeWhen,
customProps
);
if(getAppNames().indexOf(registration.name) ! = = -1)
throw Error(
formatErrorMessage(
21,
__DEV__ &&
`There is already an app registered with name ${registration.name}`,
registration.name
)
);
apps.push(
assign(
{
loadErrorTime: null.status: NOT_LOADED,
parcels: {},
devtools: {
overlays: {
options: {},
selectors: [],
},
},
},
registration
)
);
if(isInBrowser) { ensureJQuerySupport(); reroute(); }}Copy the code
The registerApplication function takes four arguments:
appNameOrConfig
: Application name, which must be globally unique. If you register an application with the same name twice, an error will be thrownappOrLoadApp
: the definition of the application used to load the application, which can be an object containing the single-SPA life cycle/method of loading the applicationactiveWhen
: The function that matches the application — activity function or the path that needs to be matched to determine whether the application should be activatedcustomProps
: Custom attributes passed to the application
UnregisterApplication — unregisterApplication
UnregisterApplication is the opposite of registerApplication, but is much simpler:
- Determine whether the application is registered. If not registered, an error is thrown
- If registered, unloadApplication is called and the application is removed from the apps list
Execution process:
The code is as follows:
export function unregisterApplication(appName) {
if (apps.filter((app) = > toName(app) === appName).length === 0) {
throw Error(
formatErrorMessage(
25,
__DEV__ &&
`Cannot unregister application '${appName}' because no such application has been registered`,
appName
)
);
}
return unloadApplication(appName).then(() = > {
const appIndex = apps.map(toName).indexOf(appName);
apps.splice(appIndex, 1);
});
}
Copy the code
UnloadApplication – unloadApplication
At the end of unregisterApplication, unloadApplication is called. After uninstalling the app, it is restored to the NOT_LOADED state and will need to be reloaded the next time it is activated.
Execute the process
The source code
export function unloadApplication(appName, opts = { waitForUnmount: false }) {
if (typeofappName ! = ="string") {
throw Error(
formatErrorMessage(
26,
__DEV__ && `unloadApplication requires a string 'appName'`)); }const app = find(apps, (App) = > toName(App) === appName);
if(! app) {throw Error(
formatErrorMessage(
27,
__DEV__ &&
`Could not unload application '${appName}' because no such application has been registered`,
appName
)
);
}
const appUnloadInfo = getAppUnloadInfo(toName(app));
if (opts && opts.waitForUnmount) {
// We need to wait for unmount before unloading the app
if (appUnloadInfo) {
// Someone else is already waiting for this, too
return appUnloadInfo.promise;
} else {
// We're the first ones wanting the app to be resolved.
const promise = new Promise((resolve, reject) = > {
addAppToUnload(app, () = > promise, resolve, reject);
});
returnpromise; }}else {
/* We should unmount the app, unload it, and remount it immediately. */
let resultPromise;
if (appUnloadInfo) {
// Someone else is already waiting for this app to unload
resultPromise = appUnloadInfo.promise;
immediatelyUnloadApp(app, appUnloadInfo.resolve, appUnloadInfo.reject);
} else {
// We're the first ones wanting the app to be resolved.
resultPromise = new Promise((resolve, reject) = > {
addAppToUnload(app, () = > resultPromise, resolve, reject);
immediatelyUnloadApp(app, resolve, reject);
});
}
returnresultPromise; }}Copy the code
During the uninstallation process, we can see the following two functions called:
addAppToUnload
: By adding the application toappToUnload
, and wait for follow-up procedureimmediatelyUnloadApp
: Immediately calls the and in the lifecycle methodunmount
andunload
Methods to uninstall the application
addAppToUnload
Applications that need to unload are added to appToUnload for later processing
export function addAppToUnload(app, promiseGetter, resolve, reject) {
appsToUnload[toName(app)] = { app, resolve, reject };
Object.defineProperty(appsToUnload[toName(app)], "promise", {
get: promiseGetter,
});
}
Copy the code
immediatelyUnloadApp
Chain calls toUnmountPromise and toUnloadPromise to unload the application
Execute the process
function immediatelyUnloadApp(app, resolve, reject) {
toUnmountPromise(app)
.then(toUnloadPromise)
.then(() = > {
resolve();
setTimeout(() = > {
// reroute, but the unload promise is done
reroute();
});
})
.catch(reject);
}
Copy the code
The resources
Configuration