Layout Engine API
The single-spa-layout library exposes several javascript functions as a public API.
Browser
In the browser, single-spa-layout exports the following functions as named exports.
constructRoutes
The constructRoutes
API transforms your Layout Definition into an opaque "resolved routes" object. We call it "opaque" because the shape of the object is irrelevant, as you will only use it when calling other APIs within single-spa-layout.
import { constructRoutes } from 'single-spa-layout';
const htmlTemplate = document.querySelector('#single-spa-template')
const layoutData = {
props: {
authToken: "78sf9d0fds89-0fysdiuf6sf8",
loggedInUser: fetch('/api/user')
},
loaders: {
mainContent: `<img src="loading.gif">`,
// A single-spa parcel config
topNav: singleSpaReact({...})
}
};
const resolvedRoutes = constructRoutes(htmlTemplate, layoutData)
Arguments
routesConfig
(required): Routes config is a JSON Layout Definition, an HTMLElement, or a parse5 HTML element. If it is an HTMLElement, it must be a<single-spa-router>
element or a<template>
that contains a single-spa-router element.layoutData
(optional): Layout data is an optionally provided object that defines props and loaders for HTML Layouts. You can omit it if using a JSON Layout or if you do not need to define props or loaders in your HTML Layout. The layoutData object should have top level propertiesprops
andloaders
that are each objects. Each of those objects' keys is the name of a prop or loader and its corresponding value.
Return value
An opaque resolvedRoutes
object. It is opaque because you will only use the object when calling other single-spa-layout APIs and do not need to read or modify the resolvedRoutes.
constructApplications
The constructApplications
API transforms your resolvedRoutes
into single-spa application registration objects. These application registration objects are then used to call singleSpa.registerApplication().
import { constructRoutes, constructApplications } from 'single-spa-layout';
import { registerApplication } from 'single-spa';
const resolvedRoutes = constructRoutes(...)
const applications = constructApplications({
routes: resolvedRoutes,
loadApp: (app) => System.import(app.name)
})
applications.forEach(registerApplication);
Arguments
constructApplications
accepts a single object as an argument, with the following properties:
routes
(required): The opaqueresolvedRoutes
object returned fromconstructRoutes
.loadApp
(required): A function that is given an application object and must return a loading function.
Return value
constructApplications
returns an array of single-spa registration objects.
constructLayoutEngine
The constructLayoutEngine
API transforms your resolvedRoutes
and applications
into a layoutEngine
object. The layout engine is responsible for creating, destroying, and rearranging dom elements during route transitions.
import { constructRoutes, constructApplications, constructLayoutEngine } from 'single-spa-layout';
import { registerApplication, start } from 'single-spa';
const resolvedRoutes = constructRoutes(...);
const applications = constructApplications(...);
const layoutEngine = constructLayoutEngine({routes: resolvedRoutes, applications: applications});
layoutEngine.isActive(); // true
layoutEngine.deactivate();
layoutEngine.activate();
applications.forEach(registerApplication);
start();
Arguments
constructLayoutEngine
accepts a single object as an argument, with the following properties:
routes
(required): The opaqueresolvedRoutes
object returned fromconstructRoutes
.applications
(required): The array of application registration objects returned fromconstructApplications
.active
(optional): A boolean that indicates whether the layout engine should start out active or not. Defaults to true.
Return Value
A layoutEngine
object, with the following properties:
-
isActive
: a function that accepts no arguments and returns a boolean indicating whether the layout engine is active or not. When active, the layout engine will change the DOM during route transitions. -
activate
: a function that accepts no arguments and returnsundefined
. Calling this function activates the layout engine, which includes setting up routing event listeners so that the layout engine can change the DOM during route transitions. -
deactivate
: a function that accepts no arguments and returnsundefined
. Calling this function deactivates the layout engine, which includes tearing down all routing event listeners so that the layout engine no longer changes the DOM during route transitions.
matchRoute
The matchRoute
API primarily exists for server rendering. It returns a filtered resolvedRoutes
object that contains only the routes that match a particular string path.
import { constructRoutes, matchRoute } from 'single-spa-layout';
const resolvedRoutes = constructRoutes(...);
const settingsRoutes = matchRoute(resolvedRoutes, "/settings")
const dashboardRoutes = matchRoute(resolvedRoutes, "/dashboard")
Arguments
routes
(required): The opaqueresolvedRoutes
object returned fromconstructRoutes
.path
(required): A string path representing the URL fragment to match the routes with. Note that the path is not a full URL - it only is the pathname part of a browser's URL. In server rendering contexts, this is often available asreq.url
.
Return Value
An opaque resolvedRoutes
object. It is opaque because you will only use the object when calling other single-spa-layout APIs and do not need to read or modify the resolvedRoutes.
Server
In NodeJS, single-spa-layout exports the following functions as named exports. Note that the code is published in ESM and therefore won't work in old versions of Node. Additionally, single-spa-layout uses package entry points, which are only supported in newer versions of Node.
// Works in newer versions of NodeJS
import "single-spa-layout";
// Works in older versions of NodeJS
import "single-spa-layout/dist/esm/single-spa-layout-server.min.js";
constructServerLayout
The constructServerLayout
api parses an HTML file and prepares it for rendering. This should be done once when the NodeJS server boots up, so the same serverLayout can be reused for all incoming HTTP requests.
import { constructServerLayout } from "single-spa-layout/server";
const serverLayout = constructServerLayout({
// filepath is resolved relative to the cwd (current working directory)
// of the NodeJS process.
filePath: "server/views/index.html",
});
// Alternatively, provide the html as a string
const serverLayout = constructServerLayout({
html: `
<html>
<head>
<single-spa-router>
<application name="nav"></application>
</single-spa-router>
</head>
</html>
`,
});
Arguments
constructServerLayout
accepts a single object argument, with the following properties:
filePath
(optional): A string file path to the HTML template file. Relative paths are resolved relative toprocess.cwd()
. IffilePath
is omitted,html
must be provided.html
(optional): An HTML string containing the HTML template. Ifhtml
is omitted,filePath
must be provided.
Return Value
constructServerLayout
returns an opaque ServerLayout object. This object is then provided to sendLayoutHTTPResponse
.
sendLayoutHTTPResponse
The sendLayoutHTTPResponse
api sends HTTP headers and HTML content to the browser. It streams a full HTML file to the browser, so that the browser shows content as soon as it is available, instead of waiting for the entire HTML document. This is done by providing a ServerResponse object, or res
to sendLayoutHTTPResponse
.
import { constructServerLayout, sendLayoutHTTPResponse } from 'single-spa-layout';
import http from 'http';
const serverLayout = constructServerLayout({...})
http.createServer((req, res) => {
sendLayoutHTTPResponse({
res,
serverLayout,
urlPath: req.path,
nonce: "yourNonceHere",
async renderApplication({ appName, propsPromise }) {
return {
assets: `<link rel="stylesheet" href="/my-styles.css">`,
content: `<button>${appName} app</button>`
}
},
async retrieveApplicationHeaders({ appName, propsPromise }) {
return {
'x-custom-header': 'value'
}
},
async renderFragment(fragmentName) {
return `<script type="systemjs-importmap">{"imports": {}}</script>`;
},
async retrieveProp(propName) {
return "prop value";
},
assembleFinalHeaders(allHeaders) {
allHeaders.forEach(({appProps, appHeaders}) => {
})
return {}
}
})
})
Arguments
sendLayoutHTTPResponse
accepts one object argument, with the following properties:
res
(required): A ServerResponse object. Expressres
objects (and likely other framework-specific objects) are supported.serverLayout
(required): The opaque server layout object returned fromconstructServerLayout
.urlPath
(required): A string url path that will be used as the current route. Example:/settings
assembleFinalHeaders
(required): A function that is passed all application headers and returns the final HTTP headers sent to the browser. The application headers are collected from theretrieveApplicationHeaders
function into an array of AppHeaders objects. Each AppHeaders object has anappName
andappHeaders
object, where the appName is a string and theappHeaders
is a headers object.assembleFinalHeaders
must return a headers object.renderApplication
(optional): A function that is given information about a single-spa application and should return the HTML content (and, optionally, the assets) for that application. This function is required if a single-spa application matches the current route. The argument passed to the renderApplication function is an object with anappName
string and apropsPromise
promise. ThepropsPromise
resolves with the props for the application. The function can return an object, string, Readable stream, or a Promise. Returned objects must be of formattype ApplicationRenderResult = { assets: Readable | Promise<Readable> | string | Promise<string>, content: Readable | Promise<Readable> | string | Promise<string> }
. Returned promises must resolve with an ApplicationRenderResult object, string or Readable stream. Theassets
returned from renderApplication are rendered into the<assets>
element in your layout definition.retrieveApplicationHeaders
(optional): A function that is given information about a single-spa application and should return the HTTP response headers for that application. This function is required if a single-spa application matches the current route. The argument passed to the retrieveApplicationHeaders function is an object with anappName
string and apropsPromise
promise. ThepropsPromise
resolves with the props for the application. The function can a headers object or a Promise that resolves with a headers object.renderFragment
(optional): A function that is given a fragment name and returns the HTML content for that fragment. This corresponds to<fragment>
elements in the layout definition, and is required if the the layout definition contains a<fragment>
element. TherenderFragment
function can return a string, Readable stream, or a Promise. Returned promises must resolve with a string or Readable stream.retrieveProp
(optional): A function that is given a propName and returns the prop's value. This function is required if any rendered applications have props.retrieveProp
can return a value, or a promise that resolves with a value.nonce
(optional): A string nonce that is added to the<script>
sent with thesingleSpaLayoutData
global variable.
Return Value
A promise that resolves when headers (but not necessarily HTTP response body) are sent.