diff --git a/.eslintrc.js b/.eslintrc.js index fc428f276..2ebf7cf2b 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,25 +4,17 @@ module.exports = { commonjs: true, es6: true, }, - extends: ['eslint:recommended', 'plugin:react/recommended', 'eslint-config-prettier'], + extends: [ + "eslint:recommended", + "plugin:react/recommended", + "eslint-config-prettier", + ], parserOptions: { ecmaFeatures: { jsx: true, }, ecmaVersion: 2018, - sourceType: 'module', - }, - plugins: ['react', 'eslint-plugin-prettier'], - rules: { - 'prettier/prettier': [ - 'error', - { - tabWidth: 2, - singleQuote: true, - trailingComma: 'all', - bracketSpacing: true, - jsxBracketSameLine: true, - } - ], + sourceType: "module", }, + plugins: ["react"], }; diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..c95dc13a9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +static/img/icons \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json index e5bca2c8a..0967ef424 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,8 +1 @@ -{ - "bracketSpacing": true, - "printWidth": 80, - "singleQuote": true, - "tabWidth": 2, - "trailingComma": "all", - "jsxBracketSameLine": true -} +{} diff --git a/blog/2016-02-26-a-case-for-soa-in-the-browser.md b/blog/2016-02-26-a-case-for-soa-in-the-browser.md index 19732ef4e..94942251f 100644 --- a/blog/2016-02-26-a-case-for-soa-in-the-browser.md +++ b/blog/2016-02-26-a-case-for-soa-in-the-browser.md @@ -47,10 +47,10 @@ You can load a sofe service either with static or asynchronous imports. ```js // Static imports -import auth from 'auth-service!sofe'; +import auth from "auth-service!sofe"; const user = auth.getLoggedInUser(); // Asynchronous imports -System.import('auth-service!sofe').then(auth => auth.getLoggedInUser()); +System.import("auth-service!sofe").then((auth) => auth.getLoggedInUser()); ``` The real power behind sofe is that services are resolved at run-time, making them unversioned. If auth-service is redeployed, it is immediately made available to all upstream dependencies. The above scenario becomes much easier to resolve because there is only one version of each shared library as services. This is powerful because it allows you to deploy once, update everywhere. Also because the code is loaded at run-time, we can also enable developer tools to override what service is loaded into your application. Or in other words, you can test code on production without actually deploying to production. diff --git a/blog/2016-12-16-a-step-by-step-guide-to-single-spa.md b/blog/2016-12-16-a-step-by-step-guide-to-single-spa.md index 240531d3e..5fa047406 100644 --- a/blog/2016-12-16-a-step-by-step-guide-to-single-spa.md +++ b/blog/2016-12-16-a-step-by-step-guide-to-single-spa.md @@ -36,7 +36,7 @@ So for now, just have a ` ``` @@ -24,14 +26,15 @@ Note that you might want to lock down the package to a specific version. See [he how to do that. ## Usage + ### Via npm ```js -import singleSpaHtml from 'single-spa-html'; +import singleSpaHtml from "single-spa-html"; const htmlLifecycles = singleSpaHtml({ - template: '', -}) + template: "", +}); export const bootstrap = htmlLifecycles.bootstrap; export const mount = htmlLifecycles.mount; @@ -39,18 +42,22 @@ export const unmount = htmlLifecycles.unmount; ``` ### Via cdn + Example usage when installed via CDN: ```js const webComponentApp = window.singleSpaHtml.default({ - template: props => ``, -}) + template: (props) => + ``, +}); -singleSpa.registerApplication('name', webComponentApp, () => true) +singleSpa.registerApplication("name", webComponentApp, () => true); ``` ## API / Options + single-spa-html is called with an object that has the following properties: + - `template` (required): An HTML string or a function that returns a string. The function will be called with the single-spa custom props. The returned string is injected into the DOM during the single-spa mount lifecycle. - `domElementGetter` (optional): A function that returns the dom element container into which the HTML will be injected. If omitted, a default implementation is provided that wraps the template in a `
` that is appended to `document.body`. diff --git a/versioned_docs/version-4.x/ecosystem-inferno.md b/versioned_docs/version-4.x/ecosystem-inferno.md index bfc26d1f9..02884ccee 100644 --- a/versioned_docs/version-4.x/ecosystem-inferno.md +++ b/versioned_docs/version-4.x/ecosystem-inferno.md @@ -11,15 +11,15 @@ single-spa-inferno is a helper library that helps implement [single-spa register First, in the application, run `npm install --save single-spa-inferno`. Then, add the following to your application's entry file. ```js -import Inferno from 'inferno'; -import rootComponent from './path-to-root-component.js'; -import singleSpaInferno from 'single-spa-inferno'; +import Inferno from "inferno"; +import rootComponent from "./path-to-root-component.js"; +import singleSpaInferno from "single-spa-inferno"; const infernoLifecycles = singleSpaInferno({ Inferno, createElement, rootComponent, - domElementGetter: () => document.getElementById('main-content'), + domElementGetter: () => document.getElementById("main-content"), }); export const bootstrap = infernoLifecyles.bootstrap; @@ -34,4 +34,4 @@ All options are passed to single-spa-inferno via the `opts` parameter when calli - `inferno`: (required) The main Inferno object, which is generally either exposed onto the window or is available via `require('inferno')` or `import Inferno from 'inferno'`. - `createElement`: (required) The default export from Inferno's `inferno-create-element` package. - `rootComponent`: (required) The top level Inferno component which will be rendered. -- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Inferno application will be bootstrapped, mounted, and unmounted. \ No newline at end of file +- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Inferno application will be bootstrapped, mounted, and unmounted. diff --git a/versioned_docs/version-4.x/ecosystem-leaked-globals.md b/versioned_docs/version-4.x/ecosystem-leaked-globals.md index 37b692474..2ec8d1950 100644 --- a/versioned_docs/version-4.x/ecosystem-leaked-globals.md +++ b/versioned_docs/version-4.x/ecosystem-leaked-globals.md @@ -9,33 +9,38 @@ that depend on global variables. Such applications are usually applications that that were popular when ES modules were not yet available. ## What single-spa-leaked-globals does + single-spa-leaked-globals will remove specific global variables from `window` during your application's [unmount lifecycle](/docs/building-applications#unmount), and add them back to `window` during your application's [mount lifecycle](/docs/building-applications#mount). ## Before using single-spa-leaked-globals + It might be okay for single-spa applications to leak some global variables. Those leaked global variables could be harmless. Below are some situations where using single-spa-leaked-globals could be useful. If your situation is not listed, consider not using single-spa-leaked-globals. 1. Your applications are accidentally sharing global variables and the order in which they are mounted matters. For example, the jQuery `$` variable - is available at the start, but app1 installs a jQuery plugin that app2 assumes is there. If app2 is mounted - before app1, you might get an error because the jQuery plugin is not installed. In that situation, the best solution is maybe to install - the jQuery plugin inside of your [single-spa config](/docs/configuration). But if that's not desireable, you can use single-spa-leaked-globals - to manage two separate versions of jQuery -- one for app1 and one for app2. + is available at the start, but app1 installs a jQuery plugin that app2 assumes is there. If app2 is mounted + before app1, you might get an error because the jQuery plugin is not installed. In that situation, the best solution is maybe to install + the jQuery plugin inside of your [single-spa config](/docs/configuration). But if that's not desireable, you can use single-spa-leaked-globals + to manage two separate versions of jQuery -- one for app1 and one for app2. 2. Your applications require different versions of the same global variable. For example, consider when app1 depends on - an [underscorejs](https://underscorejs.org/) `_` global variable and app2 depends on a [lodash](https://lodash.com/) `_` global variable. - They both need a global `_` variable, but expect different functions to be available on it. The same could be true for different versions of the - same library, such as lodash 3 vs lodash 4. In those situations, you can use single-spa-leaked-globals to make sure the `_` that is available - for app1 and app2 is the correct one. + an [underscorejs](https://underscorejs.org/) `_` global variable and app2 depends on a [lodash](https://lodash.com/) `_` global variable. + They both need a global `_` variable, but expect different functions to be available on it. The same could be true for different versions of the + same library, such as lodash 3 vs lodash 4. In those situations, you can use single-spa-leaked-globals to make sure the `_` that is available + for app1 and app2 is the correct one. ## Limitations + single-spa-leaked-globals cannot change the global nature of global dependencies. Only one instance of the global variable can be on the `window` at a time. **This means that you probably can only have one application mounted at a time that depends on that global variable.** If two applications depend on the same global variable and are [active](/docs/configuration#activity-function) at the same time, single-spa-leaked-globals won't work for you. ## Installation + ### Via npm + ```sh npm install --save single-spa-leaked-globals @@ -44,15 +49,18 @@ yarn add single-spa-leaked-globals ``` ### Via cdn + You can also use single-spa-leaked-globals via CDN, ironically as a global variable itself: + ```html ``` -Note that you should probably lock down the version of the library to avoid accidentally upgrading. See +Note that you should probably lock down the version of the library to avoid accidentally upgrading. See https://cdn.jsdelivr.net/npm/single-spa-leaked-globals/ to find the latest version. ## Usage + The single-spa-leaked-globals library is often used in conjunction with another helper library, such as single-spa-angularjs or single-spa-backbone. As such, you'll want to [export an array](/docs/building-applications#registered-application-lifecycle) for your lifecycle functions @@ -89,13 +97,16 @@ export const unmount = [ ``` If you're using single-spa-leaked-globals as a global variable itself: + ```js const leakedGlobalsLifecycles = window.singleSpaLeakedGlobals.default({ - globalVariableNames: ['_'], -}) + globalVariableNames: ["_"], +}); ``` ## API / Options + single-spa-leaked-globals is called with an object with the following properties: + - `globalVariableNames` (required): An array of strings. Each string is the name of a global variable that should - be removed when the application is unmounted, and added back when the application is mounted. \ No newline at end of file + be removed when the application is unmounted, and added back when the application is mounted. diff --git a/versioned_docs/version-4.x/ecosystem-preact.md b/versioned_docs/version-4.x/ecosystem-preact.md index 9e52beb54..3f3b9c52f 100644 --- a/versioned_docs/version-4.x/ecosystem-preact.md +++ b/versioned_docs/version-4.x/ecosystem-preact.md @@ -7,22 +7,24 @@ sidebar_label: Preact single-spa-preact is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for for use with [Preact](https://preactjs.com/). Check out the [single-spa-preact github](https://github.com/single-spa/single-spa-preact). ## Installation + ```sh npm install --save preact ``` ## Quickstart + In your project's entry file, add the following: ```js -import preact from 'preact'; -import rootComponent from './path-to-root-component.js'; -import singleSpaPreact from 'single-spa-preact'; +import preact from "preact"; +import rootComponent from "./path-to-root-component.js"; +import singleSpaPreact from "single-spa-preact"; const preactLifecycles = singleSpaPreact({ preact, rootComponent, - domElementGetter: () => document.getElementById('main-content'), + domElementGetter: () => document.getElementById("main-content"), }); export const bootstrap = preactLifecycles.bootstrap; @@ -36,4 +38,4 @@ All options are passed to single-spa-preact via the `opts` parameter when callin - `preact`: (required) The main Preact object, which is generally either exposed onto the window or is available via `require('preact')` or `import preact from 'preact'`. - `rootComponent`: (required) The top level preact component which will be rendered -- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Preact application will be bootstrapped, mounted, and unmounted. \ No newline at end of file +- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Preact application will be bootstrapped, mounted, and unmounted. diff --git a/versioned_docs/version-4.x/ecosystem-react.md b/versioned_docs/version-4.x/ecosystem-react.md index 40006fba9..60b96fac8 100644 --- a/versioned_docs/version-4.x/ecosystem-react.md +++ b/versioned_docs/version-4.x/ecosystem-react.md @@ -1,5 +1,5 @@ --- -id: ecosystem-react +id: ecosystem-react title: single-spa-react sidebar_label: React --- @@ -9,6 +9,7 @@ sidebar_label: React single-spa-react is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for use with [React](https://reactjs.org/). Check out the [single-spa-react github](https://github.com/single-spa/single-spa-react). ## Installation + ```sh npm install --save single-spa-react @@ -19,14 +20,15 @@ yarn add single-spa-react Alternatively, you can use single-spa-react by adding `` and accessing the singleSpaReact global variable. ## Quickstart + Your bundler's "entry file" should look like this, which allows your application to be downloaded as an in-browser ES module. ```js -import React from 'react'; -import ReactDOM from 'react-dom'; -import rootComponent from './path-to-root-component.js'; +import React from "react"; +import ReactDOM from "react-dom"; +import rootComponent from "./path-to-root-component.js"; // Note that SingleSpaContext is a react@16.3 (if available) context that provides the singleSpa props -import singleSpaReact, {SingleSpaContext} from 'single-spa-react'; +import singleSpaReact, { SingleSpaContext } from "single-spa-react"; const reactLifecycles = singleSpaReact({ React, @@ -47,7 +49,7 @@ All options are passed to single-spa-react via the `opts` parameter when calling - `ReactDOM`: (required) The main ReactDOMbject, which is available via `require('react-dom')` `import ReactDOM from 'react-dom'`. - `rootComponent`: (required) The top level React component which will be rendered. Can be omitted only if `loadRootComponent` is provided. - `loadRootComponent`: (optional) A loading function that returns a promise that resolves with the parcel. This takes the place of the `rootComponent` opt, when provided. It is intended to help people - who want to lazy load the source code for their root component. The source code will be lazy loaded during the bootstrap lifecycle. + who want to lazy load the source code for their root component. The source code will be lazy loaded during the bootstrap lifecycle. - `suppressComponentDidCatchWarning`: (optional) A boolean that indicates if single-spa-react should warn when the rootComponent does not implement componentDidCatch. Defaults to false. - `domElementGetter`: (optional) A function that takes in no arguments and returns a DOMElement. This dom element is where the React application will be bootstrapped, mounted, and unmounted. Note that this opt can be omitted. When omitted, the `domElementGetter` or `domElement` @@ -68,6 +70,7 @@ implemented. See https://reactjs.org/blog/2017/07/26/error-handling-in-react-16. ## SingleSpaContext ## Parcels + single-spa-react can also be used to create a single-spa parcel (instead of a single-spa application). To do so, simply call singleSpaReact() the same as for an application, except without a domElementGetter (since those are provided by the code that will mount the parcel). @@ -75,17 +78,19 @@ Additionally, single-spa-react provides a `` component to make using fra You can use the Parcel component either by npm installing the library and importing `single-spa-react/parcel` or by adding `` and then accessing the Parcel component with `window.Parcel.default`. #### Parcel props + - `config` (required): Either a single-spa parcel config object, or a "loading function" that returns a Promise that resolves with the parcel config. - `wrapWith` (optional): A string [tagName](https://developer.mozilla.org/en-US/docs/Web/API/Element/tagName).`` will create a dom node of that type for the parcel to be mounted into. Defaults to `div` - `appendTo` (optional): A dom element to append the parcel to. By default, this is not needed because the parcel will be mounted in the DOM that the `` component was rendered into. Useful for appending parcels to document.body or other separate parts of the dom. - `mountParcel` (sometimes required, sometimes not): The `mountParcel` function provided by single-spa. In general, it is preferred to use an application's mountParcel function instead of the - single-spa's root mountParcel function, so that single-spa can keep track of the parent-child relationship and automatically unmount the application's parcels when the application unmounts. - Note that if the `` component is being rendered by a single-spa application that uses single-spa-react, it is **unnecessary** to pass in the prop, since `` can get the prop - from [SingleSpaContext](#singlespacontext) + single-spa's root mountParcel function, so that single-spa can keep track of the parent-child relationship and automatically unmount the application's parcels when the application unmounts. + Note that if the `` component is being rendered by a single-spa application that uses single-spa-react, it is **unnecessary** to pass in the prop, since `` can get the prop + from [SingleSpaContext](#singlespacontext) - `handleError` (optional): A function that will be called with errors thrown by the parcel. If not provided, errors will be thrown on the window, by default. - `parcelDidMount` (optional): A function that will be called when the parcel finishes loading and mounting. #### Examples + ```jsx import Parcel from 'single-spa-react/parcel' import * as parcelConfig from './my-parcel.js' @@ -131,4 +136,5 @@ import * as parcelConfig from './my-parcel.js' ``` ## Create React App + See [FAQ for CRA](https://single-spa.js.org/docs/faq#create-react-app) diff --git a/versioned_docs/version-4.x/ecosystem-riot.md b/versioned_docs/version-4.x/ecosystem-riot.md index 21710f854..5e991b419 100644 --- a/versioned_docs/version-4.x/ecosystem-riot.md +++ b/versioned_docs/version-4.x/ecosystem-riot.md @@ -13,6 +13,7 @@ single-spa-riot is a helper library that helps implement [single-spa registered [![minified](https://badgen.net/bundlephobia/minzip/single-spa-riot)](https://bundlephobia.com/result?p=single-spa-riot) ## Installation + ```sh npm install --save single-spa-riot ``` @@ -20,13 +21,13 @@ npm install --save single-spa-riot ## Usage ```js -import * as Riot from 'riot'; -import singleSpaRiot from 'single-spa-riot'; -import App from './App.riot' +import * as Riot from "riot"; +import singleSpaRiot from "single-spa-riot"; +import App from "./App.riot"; const riotLifecycles = singleSpaRiot({ rootComponent: Riot.component(App), - domElementGetter: () => document.getElementById('#app') + domElementGetter: () => document.getElementById("#app"), }); export const bootstrap = riotLifecycles.bootstrap; @@ -42,4 +43,4 @@ All options are passed to single-spa-riot via the `opts` parameter when calling - `domElementGetter`: (required) the callback to get root component mount element. - `rootComponent`: (optional and replaces `appOptions.loadRootComponent`) the root riot component. -- `loadRootComponent`: (optional and replaces `appOptions.rootComponent`) A promise that resolves with your root component. This is useful for lazy loading. \ No newline at end of file +- `loadRootComponent`: (optional and replaces `appOptions.rootComponent`) A promise that resolves with your root component. This is useful for lazy loading. diff --git a/versioned_docs/version-4.x/ecosystem-svelte.md b/versioned_docs/version-4.x/ecosystem-svelte.md index 6ef20049c..070d3f98a 100644 --- a/versioned_docs/version-4.x/ecosystem-svelte.md +++ b/versioned_docs/version-4.x/ecosystem-svelte.md @@ -11,13 +11,13 @@ single-spa-svelte is a helper library that helps implement [single-spa registere First, in the [single-spa application](https://github.com/single-spa/single-spa/blob/master/docs/applications.md#registered-applications), run `npm install --save single-spa-svelte`. Then, create an entry file with the following. ```js -import singleSpaSvelte from 'single-spa-svelte'; -import myRootSvelteComponent from 'my-root-svelte-component.js'; +import singleSpaSvelte from "single-spa-svelte"; +import myRootSvelteComponent from "my-root-svelte-component.js"; const svelteLifecycles = singleSpaSvelte({ component: myRootSvelteComponent, - domElementGetter: () => document.getElementById('svelte-app'), - data: { someData: 'data' } + domElementGetter: () => document.getElementById("svelte-app"), + data: { someData: "data" }, }); export const bootstrap = svelteLifecycles.bootstrap; diff --git a/versioned_docs/version-4.x/ecosystem-vue.md b/versioned_docs/version-4.x/ecosystem-vue.md index 83c809236..98e2f699b 100644 --- a/versioned_docs/version-4.x/ecosystem-vue.md +++ b/versioned_docs/version-4.x/ecosystem-vue.md @@ -7,13 +7,17 @@ sidebar_label: Vue single-spa-vue is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for for use with [Vue.js](https://vuejs.org/). Check out the [single-spa-vue github](https://github.com/single-spa/single-spa-vue). ## Starter repo + For a full example, see [coexisting-vue-microfrontends](https://github.com/joeldenning/coexisting-vue-microfrontends). ## Live demo + https://coexisting-vue-microfrontends.surge.sh ## Installation + ### Vue CLI + The [vue-cli-plugin-single-spa](https://github.com/single-spa/vue-cli-plugin-single-spa) will get everything set up. ```sh @@ -21,46 +25,48 @@ vue add single-spa ``` The CLI Plugin does the following for you: -1) Modify your webpack config so that your project works as a single-spa application or parcel. -2) Install [single-spa-vue](https://github.com/single-spa/single-spa-vue). -3) Modify your `main.js` or `main.ts` file so that your project works as a single-spa application or parcel. -4) Add a `set-public-path.js` that will use `systemjs-webpack-interop` in order to set the public path of your application. + +1. Modify your webpack config so that your project works as a single-spa application or parcel. +2. Install [single-spa-vue](https://github.com/single-spa/single-spa-vue). +3. Modify your `main.js` or `main.ts` file so that your project works as a single-spa application or parcel. +4. Add a `set-public-path.js` that will use `systemjs-webpack-interop` in order to set the public path of your application. ### Without Vue CLI + ```sh npm install --save single-spa-vue ``` -Alternatively, you can use single-spa-vue by adding `` to your HTML file and +Alternatively, you can use single-spa-vue by adding `` to your HTML file and accessing the `singleSpaVue` global variable. ## Usage + Install `systemjs-webpack-interop` if you have not already done so. `npm install systemjs-webpack-interop -S` -Create a file at the same level as your `main.js/ts` called `set-public-path.js` +Create a file at the same level as your `main.js/ts` called `set-public-path.js` ```js -import { setPublicPath } from 'systemjs-webpack-interop'; - -setPublicPath('appName'); +import { setPublicPath } from "systemjs-webpack-interop"; +setPublicPath("appName"); ``` Change your application's entry file to be the following. ```js -import './set-public-path'; -import Vue from 'vue'; -import App from './App.vue'; -import router from './router'; -import singleSpaVue from 'single-spa-vue'; +import "./set-public-path"; +import Vue from "vue"; +import App from "./App.vue"; +import router from "./router"; +import singleSpaVue from "single-spa-vue"; const vueLifecycles = singleSpaVue({ Vue, appOptions: { - render: h => h(App), + render: (h) => h(App), router, }, }); @@ -68,13 +74,13 @@ const vueLifecycles = singleSpaVue({ export const bootstrap = vueLifecycles.bootstrap; export const mount = vueLifecycles.mount; export const unmount = vueLifecycles.unmount; - ``` Note that if you are using the Vue CLI Plugin, your `main.ts` or `main.js` file will be updated with this code automatically and the `set-public-path.js` file will automatically be created with the app name being your package.json's name property. ## Shared dependencies + For performance, it is best to share a single version and instance of Vue, Vue Router, and other large libraries. To do this, add your shared dependencies as [webpack externals](https://webpack.js.org/configuration/externals). Then you use @@ -87,21 +93,23 @@ Sharing a single instance of Vue and other common libraries is highly recommende [recommended setup for single-spa](https://single-spa.js.org/docs/faq#is-there-a-recommended-setup) for more details on why. ### Shared deps with Vue CLI + ```js // vue.config.js module.exports = { - chainWebpack: config => { - config.externals(['vue', 'vue-router']) - } -} + chainWebpack: (config) => { + config.externals(["vue", "vue-router"]); + }, +}; ``` ### Shared deps without Vue CLI + ```js // webpack.config.js module.exports = { - externals: ['vue', 'vue-router'], -} + externals: ["vue", "vue-router"], +}; ``` ## Options @@ -113,10 +121,12 @@ All options are passed to single-spa-vue via the `opts` parameter when calling ` - `loadRootComponent`: (optional and replaces `appOptions.render`) A promise that resolves with your root component. This is useful for lazy loading. ## As a single-spa parcel + To create a single-spa parcel, simply omit the `el` option from your appOptions, since the dom element will be specified by the user of the Parcel. Every other option should be provided exactly the same as in the example above. ## Custom Props + [single-spa custom props](/docs/building-applications#custom-props) are added to your App component as `appOptions.data`, and are accessible via `vm.$data`. See [this Vue documentation](https://vuejs.org/v2/api/#data) for more information on `appOptions.data`. diff --git a/versioned_docs/version-4.x/ecosystem.md b/versioned_docs/version-4.x/ecosystem.md index fa15d699b..62ee76b96 100644 --- a/versioned_docs/version-4.x/ecosystem.md +++ b/versioned_docs/version-4.x/ecosystem.md @@ -7,6 +7,7 @@ sidebar_label: Overview The single-spa ecosystem is quickly growing to support as many frameworks and build tools as possible. ## Help for frameworks + There is a growing number of projects that help you bootstrap, mount, and unmount your applications that are written with popular frameworks. Feel free to contribute to this list with your own project: @@ -24,51 +25,63 @@ to contribute to this list with your own project: - [single-spa-backbone](./ecosystem-backbone.md) ## Webpack 2+ + With webpack 2+, we can take advantage of its support for [code splitting](https://webpack.js.org/guides/code-splitting/) with [import()](https://webpack.js.org/api/module-methods/#import) in order to easily lazy-load registered applications when they are needed. When registering registered applications from inside of your single spa config, try the following for your [loading functions](configuration#loading-function). + ```js -import {registerApplication} from 'single-spa'; +import { registerApplication } from "single-spa"; -registerApplication('app-name', () => import('./my-app.js'), activeWhen); +registerApplication("app-name", () => import("./my-app.js"), activeWhen); function activeWhen() { - return window.location.pathname.indexOf('/my-app') === 0; + return window.location.pathname.indexOf("/my-app") === 0; } ``` ## SystemJS + Since SystemJS is a Promise-based [loader](https://whatwg.github.io/loader), the way to lazy load your registered applications is straightforward: ```js -import {registerApplication} from 'single-spa'; +import { registerApplication } from "single-spa"; // Import the registered application with a SystemJS.import call -registerApplication('app-name-1', () => SystemJS.import('./my-app.js'), activeWhen); +registerApplication( + "app-name-1", + () => SystemJS.import("./my-app.js"), + activeWhen, +); // Alternatively, use the more out-of-date System.import (instead of SystemJS.import) -registerApplication('app-name-2', () => System.import('./my-other-app.js'), activeWhen); +registerApplication( + "app-name-2", + () => System.import("./my-other-app.js"), + activeWhen, +); function activeWhen() { - return window.location.pathname.indexOf('/my-app') === 0; + return window.location.pathname.indexOf("/my-app") === 0; } ``` ## Webpack 1 + With webpack 1, there is no support for Promise-based code splitting. Instead, we have to either wrap a require.ensure in a Promise, or just give up on lazy loading completely. ```js -import {registerApplication} from 'single-spa'; -import app1 from './app1'; // Not lazy loading with code splitting :( +import { registerApplication } from "single-spa"; +import app1 from "./app1"; // Not lazy loading with code splitting :( // Giving up on lazy loading and code splitting :( -registerApplication('app-1', () => Promise.resolve(app1), activeWhen); +registerApplication("app-1", () => Promise.resolve(app1), activeWhen); // Still doing code splitting! But verbose :( -registerApplication('app-2', app2InPromise, activeWhen); +registerApplication("app-2", app2InPromise, activeWhen); /* Unfortunately, this logic cannot be abstracted into a generic * function that handles wrapping require.ensure in a promise for @@ -77,18 +90,18 @@ registerApplication('app-2', app2InPromise, activeWhen); * calls at build-time, so you can't pass variables into require.ensure. */ function app2InPromise() { - return new Promise((resolve, reject) => { - require.ensure(['./app-2.js'], require => { - try { - resolve(require('./app-2.js')); - } catch(err) { - reject(err); - } - }); - }); + return new Promise((resolve, reject) => { + require.ensure(["./app-2.js"], (require) => { + try { + resolve(require("./app-2.js")); + } catch (err) { + reject(err); + } + }); + }); } function activeWhen() { - return window.location.pathname.indexOf('/my-app') === 0; + return window.location.pathname.indexOf("/my-app") === 0; } ``` diff --git a/versioned_docs/version-4.x/examples.md b/versioned_docs/version-4.x/examples.md index fcdd47b99..9886aaf6d 100644 --- a/versioned_docs/version-4.x/examples.md +++ b/versioned_docs/version-4.x/examples.md @@ -5,6 +5,7 @@ sidebar_label: Resources --- There are a variety of single-spa example repositories, each for different use cases: + - [coexisting-angular-microfrontends](https://github.com/joeldenning/coexisting-angular-microfrontends) is a full blown Angular 7 microfrontends repo that combines three separate Angular CLI projects into one page. - [coexisting-vue-microfrontends](https://github.com/joeldenning/coexisting-vue-microfrontends) shows three separate Vue CLI projects existing within one page. - [single-spa-portal-example](https://gitlab.com/TheMcMurder/single-spa-portal-example) is a great example of coexisting React microfrontends. diff --git a/versioned_docs/version-4.x/faq.md b/versioned_docs/version-4.x/faq.md index f7dc7801b..fb4906320 100644 --- a/versioned_docs/version-4.x/faq.md +++ b/versioned_docs/version-4.x/faq.md @@ -125,9 +125,9 @@ Single spa supports code splits. There are so many ways to code split we won't b - For SystemJS >= 6, use [systemjs-webpack-interop](https://github.com/joeldenning/systemjs-webpack-interop): ```js - import { setPublicPath } from 'systemjs-webpack-interop'; + import { setPublicPath } from "systemjs-webpack-interop"; - setPublicPath('name-of-module-in-import-map'); + setPublicPath("name-of-module-in-import-map"); ``` - For SystemJS 2-5: Find a code example [here](https://gitlab.com/TheMcMurder/single-spa-portal-example/blob/master/people/src/set-public-path.js#L3) diff --git a/versioned_docs/version-4.x/getting-started-overview.md b/versioned_docs/version-4.x/getting-started-overview.md index 08198aa70..4e99919a9 100644 --- a/versioned_docs/version-4.x/getting-started-overview.md +++ b/versioned_docs/version-4.x/getting-started-overview.md @@ -29,11 +29,12 @@ single-spa apps consist of the following: 1. [Applications](building-applications.md), each of which is an entire SPA itself (sort of). Each application can respond to url routing events and must know how to bootstrap, mount, and unmount itself from the DOM. The main difference between a traditional SPA and single-spa applications is that they must be able to coexist with other applications, and they do not each have their own HTML page. - For example, your React or Angular SPAs are applications. When active, they listen to url routing events and put content on the DOM. When inactive, they do not listen to url routing events and are totally removed from the DOM. + For example, your React or Angular SPAs are applications. When active, they listen to url routing events and put content on the DOM. When inactive, they do not listen to url routing events and are totally removed from the DOM. + 2. A [single-spa-config](configuration), which is the HTML page _and_ the JavaScript that registers applications with single-spa. Each application is registered with three things: - - A name - - A function to load the application's code - - A function that determines when the application is active/inactive + - A name + - A function to load the application's code + - A function that determines when the application is active/inactive ## How hard will it be to use single-spa? @@ -43,8 +44,8 @@ Our objective is to make using single-spa as easy as possible. But we should als If you're not starting your application from scratch, you'll have to [migrate your SPA](migrating-existing-spas.md) to become a single-spa application. -* [React - Migrating to single-spa](migrating-react-tutorial.md) -* [AngularJS - Migrating to single-spa](migrating-angularJS-tutorial.md) +- [React - Migrating to single-spa](migrating-react-tutorial.md) +- [AngularJS - Migrating to single-spa](migrating-angularJS-tutorial.md) single-spa works in Chrome, Firefox, Safari, IE11, and Edge. @@ -56,14 +57,14 @@ Yep. The documentation is divided into several sections: -* [Getting Started](getting-started-overview.md) -* [single-spa Applications](building-applications.md) -* [single-spa Parcels](parcels-overview.md) -* [Examples](examples.md) -* [Ecosystem](ecosystem.md) -* [Contributing Guide](contributing-overview.md) -* [Blog](https://single-spa.js.org/blog/) -* [Where to Get Support](https://single-spa.js.org/help/) +- [Getting Started](getting-started-overview.md) +- [single-spa Applications](building-applications.md) +- [single-spa Parcels](parcels-overview.md) +- [Examples](examples.md) +- [Ecosystem](ecosystem.md) +- [Contributing Guide](contributing-overview.md) +- [Blog](https://single-spa.js.org/blog/) +- [Where to Get Support](https://single-spa.js.org/help/) You can help improve the single-spa website by sending pull requests to the [`single-spa.js.org` repository](https://github.com/single-spa/single-spa.js.org). @@ -77,29 +78,29 @@ To create a single-spa application, you will need to do three things: ```html - - - + + + ``` 2. Create a single-spa-config. Check out the [docs](configuration) for more detail. ```js -import * as singleSpa from 'single-spa'; +import * as singleSpa from "single-spa"; -const appName = 'app1'; +const appName = "app1"; /* The loading function is a function that returns a promise that resolves with the JavaScript application module. * The purpose of it is to facilitate lazy loading -- single-spa will not download the code for a application until it needs to. * In this example, import() is supported in webpack and returns a Promise, but single-spa works with any loading function that returns a Promise. */ -const loadingFunction = () => import('./app1/app1.js'); +const loadingFunction = () => import("./app1/app1.js"); /* single-spa does some top-level routing to determine which application is active for any url. You can implement this routing any way you'd like. * One useful convention might be to prefix the url with the name of the app that is active, to keep your top-level routing simple. */ -const activityFunction = location => location.pathname.startsWith('/app1'); +const activityFunction = (location) => location.pathname.startsWith("/app1"); singleSpa.registerApplication(appName, loadingFunction, activityFunction); singleSpa.start(); @@ -113,31 +114,25 @@ singleSpa.start(); let domEl; export function bootstrap(props) { - return Promise - .resolve() - .then(() => { - domEl = document.createElement('div'); - domEl.id = 'app1'; - document.body.appendChild(domEl); - }); + return Promise.resolve().then(() => { + domEl = document.createElement("div"); + domEl.id = "app1"; + document.body.appendChild(domEl); + }); } export function mount(props) { - return Promise - .resolve() - .then(() => { - // This is where you would normally use a framework to mount some ui to the dom. See https://single-spa.js.org/docs/ecosystem.html. - domEl.textContent = 'App 1 is mounted!' - }); + return Promise.resolve().then(() => { + // This is where you would normally use a framework to mount some ui to the dom. See https://single-spa.js.org/docs/ecosystem.html. + domEl.textContent = "App 1 is mounted!"; + }); } export function unmount(props) { - return Promise - .resolve() - .then(() => { - // This is normally where you would tell the framework to unmount the ui from the dom. See https://single-spa.js.org/docs/ecosystem.html - domEl.textContent = ''; - }) + return Promise.resolve().then(() => { + // This is normally where you would tell the framework to unmount the ui from the dom. See https://single-spa.js.org/docs/ecosystem.html + domEl.textContent = ""; + }); } ``` diff --git a/versioned_docs/version-4.x/migrating-angularJS-tutorial.md b/versioned_docs/version-4.x/migrating-angularJS-tutorial.md index 22c83923b..e450c1719 100644 --- a/versioned_docs/version-4.x/migrating-angularJS-tutorial.md +++ b/versioned_docs/version-4.x/migrating-angularJS-tutorial.md @@ -79,7 +79,7 @@ Start by stubbing out the registration function by adding the following in `publ ```js title="public/single-spa.config.js" window.singleSpa.registerApplication( - 'drum-machine', + "drum-machine", loadingFunction, function activityFunction() { return true; @@ -159,7 +159,7 @@ Currently, our _index.html_ contains two hurdles we will need to overcome to all In _index.html_ remove `ng-app="AngularDrumMachine`. ```html - + @@ -274,13 +274,13 @@ Then, inside of `display-machine.directive.js` we will register our new directiv Add the following code to _public/app/directives/display-machine.directive.js_`\*: ```js -'use strict'; +"use strict"; -angular.module('AngularDrumMachine').directive('displayMachine', [ - function() { +angular.module("AngularDrumMachine").directive("displayMachine", [ + function () { return { - restrict: 'E', - templateUrl: 'assets/templates/display-machine.template.html', + restrict: "E", + templateUrl: "assets/templates/display-machine.template.html", }; }, ]); diff --git a/versioned_docs/version-4.x/migrating-existing-spas.md b/versioned_docs/version-4.x/migrating-existing-spas.md index 74a815d1c..20ccb75f3 100644 --- a/versioned_docs/version-4.x/migrating-existing-spas.md +++ b/versioned_docs/version-4.x/migrating-existing-spas.md @@ -13,6 +13,7 @@ need to do three things: See [docs](configuration#indexhtml-file). ## Converting SPAs into registered applications + Your existing SPAs, whether they be Angular, React, or something else, probably are not used to unmounting themselves from the DOM. Also, they probably have had the luxury of controlling the entire HTML page themselves, instead of being purely JavaScript applications @@ -21,14 +22,16 @@ into single-spa registered applications, they will need to overcome those obstac lifecycle functions. ### (1) Implementing lifecycle functions + See the [registered application lifecycle](building-applications.md#registered-application-lifecycle) docs to see what you need to do. The hardest part will almost certainly be the `unmount` lifecycle, since most SPAs aren't accustomed to going dormant and unmounting themselves from the DOM. When implementing your lifecycle functions, first check out the [ecosystem](ecosystem.md) docs before reinventing the wheel yourself. If that doesn't have everything you need, you'll have to make sure that your -SPA can clean up its DOM, DOM event listeners (all of them, but *especially* hashchange and popstate), +SPA can clean up its DOM, DOM event listeners (all of them, but _especially_ hashchange and popstate), and memory. ### (2) Getting the CSS, fonts, ` ``` + 5. Confirm that your application now is mounting again and works properly. Also, check that it's in `MOUNTED` status as a single-spa microfrontend: ```js // in the browser console, check that it's in `MOUNTED` status -console.log('legacyAngularjsApp status', singleSpa.getAppStatus('legacyAngularjsApp')); +console.log( + "legacyAngularjsApp status", + singleSpa.getAppStatus("legacyAngularjsApp"), +); ``` ### Step 2: Convert to SystemJS module: @@ -270,13 +282,17 @@ In single-spa, it's encouraged to split microfrontends by route. During the migr It's recommended to create new microfrontends via the [single-spa CLI](/docs/create-single-spa). 1. Add a new call to `registerApplication()` to your index.html file. + ```js window.singleSpa.registerApplication({ name: "new-microfrontend", - app: function () { return System.import("new-microfrontend"); }, - activeWen: ["/route-for-new-microfrontend"] -}) + app: function () { + return System.import("new-microfrontend"); + }, + activeWen: ["/route-for-new-microfrontend"], +}); ``` + 2. Add the new microfrontend to your import map in the index.html file. ```html @@ -290,6 +306,7 @@ window.singleSpa.registerApplication({ } ``` + 3. Start a new microfrontend on the port in the import map. Go to the route for the new microfrontend and verify it is loaded. ## Examples diff --git a/versioned_docs/version-5.x/ecosystem-backbone.md b/versioned_docs/version-5.x/ecosystem-backbone.md index d1a124d3f..e1e2be1e2 100644 --- a/versioned_docs/version-5.x/ecosystem-backbone.md +++ b/versioned_docs/version-5.x/ecosystem-backbone.md @@ -11,19 +11,19 @@ A single-spa helper library which provides lifecycle events for building single- There are mostly three styles of creating backbone applications -1. Using [RequireJS](https://requirejs.org/) which will loads the application and all it's dependencies, including the templates loaded using [Handlebars](https://handlebarsjs.com/), [RequireJS:Text](https://github.com/requirejs/text) or any other engine. +1. Using [RequireJS](https://requirejs.org/) which will loads the application and all it's dependencies, including the templates loaded using [Handlebars](https://handlebarsjs.com/), [RequireJS:Text](https://github.com/requirejs/text) or any other engine. If your application is written using this style, then you will have to pass the `AppWithRequire` parameter as options in the plugin, and choose the flavour to load the app, either through `data-main` attribute or without it. 2. Using [Backbone](http://backbonejs.org/) and ApplicationPath (Entry point of application) directly as script elements and optionally loading other dependencies. -3. Loading a single application bundle which includes application dependencies like i.e. Backbone, Require, Underscore, Jquery etc. +3. Loading a single application bundle which includes application dependencies like i.e. Backbone, Require, Underscore, Jquery etc. ## NPM package npm install --save @emtecinc/single-spa-backbone -The npm package can be [found here](https://www.npmjs.com/package/@emtecinc/single-spa-backbone). +The npm package can be [found here](https://www.npmjs.com/package/@emtecinc/single-spa-backbone). ## Quickstart @@ -32,42 +32,32 @@ The npm package can be [found here](https://www.npmjs.com/package/@emtecinc/sing First, in the [single-spa application](https://github.com/single-spa/single-spa/blob/master/docs/applications.md#registered-applications), run `npm install --save @emtec/single-spa-backbone`. Then, create an entry file for application like below, assuming the application has some `BasePath` with `AppPath` and `RequireJsPath' being relative to the base path. ```js -import singleSpaBackbone from '@emtecinc/single-spa-backbone'; +import singleSpaBackbone from "@emtecinc/single-spa-backbone"; const backBoneLifecycles = singleSpaBackbone({ - BasePath: 'appBasePath', - AppWithRequire: - { - IsDataMain: true, - AppPath: 'src/app', - RequireJsPath: 'lib/require.js' - }, - DomElementSetter: domElementSetter + BasePath: "appBasePath", + AppWithRequire: { + IsDataMain: true, + AppPath: "src/app", + RequireJsPath: "lib/require.js", + }, + DomElementSetter: domElementSetter, }); -export const bootstrap = [ - backBoneLifecycles.bootstrap, -]; +export const bootstrap = [backBoneLifecycles.bootstrap]; -export const mount = [ - backBoneLifecycles.mount, -]; - -export const unmount = [ - backBoneLifecycles.unmount, -]; +export const mount = [backBoneLifecycles.mount]; +export const unmount = [backBoneLifecycles.unmount]; function domElementSetter() { - - //use the same element id to render into, in the backbone app - let el = document.getElementById('shell-container'); - if (!el) { - el = document.createElement('div'); - el.id = 'shell-container'; - document.body.appendChild(el); - } - + //use the same element id to render into, in the backbone app + let el = document.getElementById("shell-container"); + if (!el) { + el = document.createElement("div"); + el.id = "shell-container"; + document.body.appendChild(el); + } } ``` @@ -75,22 +65,20 @@ function domElementSetter() { Please note that this hook up is just a setter and don't expect you to return a value. You need to explicitly use the same element #id in the backbone application to use it as app region or container. - ### Option 2: Using `RequireJS` without `data-main` `IsDataMain` will be set to `false` in this case ```js -import singleSpaBackbone from '@emtecinc/single-spa-backbone'; +import singleSpaBackbone from "@emtecinc/single-spa-backbone"; const backBoneLifecycles = singleSpaBackbone({ - BasePath: 'appBasePath', - AppWithBackboneJs: - { - AppPath: 'src/app', - BackboneJsPath: 'lib/backbone.js' - }, - DomElementSetter: domElementSetter + BasePath: "appBasePath", + AppWithBackboneJs: { + AppPath: "src/app", + BackboneJsPath: "lib/backbone.js", + }, + DomElementSetter: domElementSetter, }); export const bootstrap = backBoneLifecycles.bootstrap; @@ -100,31 +88,27 @@ export const mount = backBoneLifecycles.mount; export const unmount = backBoneLifecycles.unmount; function domElementSetter() { - - //use the same element id to render into, in the backbone app - let el = document.getElementById('shell-container'); - if (!el) { - el = document.createElement('div'); - el.id = 'shell-container'; - document.body.appendChild(el); - } - + //use the same element id to render into, in the backbone app + let el = document.getElementById("shell-container"); + if (!el) { + el = document.createElement("div"); + el.id = "shell-container"; + document.body.appendChild(el); + } } ``` ### Option 3: Load Backbone app using production build - ```js -import singleSpaBackbone from '@emtecinc/single-spa-backbone'; +import singleSpaBackbone from "@emtecinc/single-spa-backbone"; const backBoneLifecycles = singleSpaBackbone({ - BasePath: 'appBasePath', - App: - { - AppPath: 'src/app' - }, - DomElementSetter: domElementSetter + BasePath: "appBasePath", + App: { + AppPath: "src/app", + }, + DomElementSetter: domElementSetter, }); export const bootstrap = backBoneLifecycles.bootstrap; @@ -133,42 +117,40 @@ export const mount = backBoneLifecycles.mount; export const unmount = backBoneLifecycles.unmount; - function domElementSetter() { - - //use the same element id to render into, in the backbone app - let el = document.getElementById('shell-container'); - if (!el) { - el = document.createElement('div'); - el.id = 'shell-container'; - document.body.appendChild(el); - } - + //use the same element id to render into, in the backbone app + let el = document.getElementById("shell-container"); + if (!el) { + el = document.createElement("div"); + el.id = "shell-container"; + document.body.appendChild(el); + } } ``` - ## Options All options are passed to single-spa-backbone via the `userOptions` parameter when calling `singleSpaBackbone(userOptions)`. The following properties are available: -* `BasePath` (required) : The base path of the backbone application. Mostly it will be the public path from where the app is server and other paths will be relative to this. This parameter expects a string type. -optional +- `BasePath` (required) : The base path of the backbone application. Mostly it will be the public path from where the app is server and other paths will be relative to this. This parameter expects a string type. + optional + +- `AppWithRequire` (required) : This parameter takes an object and expects below properties: + + - `IsDataMain` (optional) : This parameter takes a boolean value and is used to specify whether require js will use `data-main` to load the app. + - `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is entry point of your application and will be booted up using RequireJs. The path is relative to BasePath. + - `RequireJsPath` (required) : This parameter takes a string value and takes the path of the RequireJs file and is relative to BasePath. + - `DependenciesJsPaths` (optional) : This is an optional parameter takes an array of strings. It can be used to optionally provide a list of JavaScript paths which you want to load in the browser. -* `AppWithRequire` (required) : This parameter takes an object and expects below properties: - * `IsDataMain` (optional) : This parameter takes a boolean value and is used to specify whether require js will use `data-main` to load the app. - * `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is entry point of your application and will be booted up using RequireJs. The path is relative to BasePath. - * `RequireJsPath` (required) : This parameter takes a string value and takes the path of the RequireJs file and is relative to BasePath. - * `DependenciesJsPaths` (optional) : This is an optional parameter takes an array of strings. It can be used to optionally provide a list of JavaScript paths which you want to load in the browser. +- `AppWithBackboneJs` (optional) : This parameter takes an object and expects below properties: -* `AppWithBackboneJs` (optional) : This parameter takes an object and expects below properties: - * `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is entry point of your application and will be booted up using Backbone Js. The path is relative to BasePath. - * `BackboneJsPath` (required) : This parameter takes a string value and takes the path of the Backbone Js file and is relative to BasePath. - * `DependenciesJsPaths` (optional) : This is an optional parameter takes an array of strings. It can be used to optionally provide a list of JavaScript paths which you want to load in the browser. + - `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is entry point of your application and will be booted up using Backbone Js. The path is relative to BasePath. + - `BackboneJsPath` (required) : This parameter takes a string value and takes the path of the Backbone Js file and is relative to BasePath. + - `DependenciesJsPaths` (optional) : This is an optional parameter takes an array of strings. It can be used to optionally provide a list of JavaScript paths which you want to load in the browser. -* `App` (optional) : This parameter takes an object and expects below properties: - * `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is the production build of your backbone application. The path is relative to BasePath. +- `App` (optional) : This parameter takes an object and expects below properties: + - `AppPath` (required) : This parameter takes a string value and specifies the path of the JavaScript file, which is the production build of your backbone application. The path is relative to BasePath. -### Note : Out of AppWithRequire, AppWithBackboneJs and App only one is required +### Note : Out of AppWithRequire, AppWithBackboneJs and App only one is required -* `DomElementSetter` (optional) : This is an optional parameter and can be mostly used to create a dom element, whose id can be later used in the backbone app to load the application. However, you can freely use this callback for any other purpose. It is called before anything else. \ No newline at end of file +- `DomElementSetter` (optional) : This is an optional parameter and can be mostly used to create a dom element, whose id can be later used in the backbone app to load the application. However, you can freely use this callback for any other purpose. It is called before anything else. diff --git a/versioned_docs/version-5.x/ecosystem-css.md b/versioned_docs/version-5.x/ecosystem-css.md index 7d961f36c..c53c2c3bd 100644 --- a/versioned_docs/version-5.x/ecosystem-css.md +++ b/versioned_docs/version-5.x/ecosystem-css.md @@ -52,7 +52,7 @@ Browsers support [CSS custom properties](https://developer.mozilla.org/en-US/doc ```css /* In your styleguide / design system */ :root { - --blue: #0000FF; + --blue: #0000ff; } ``` @@ -172,15 +172,15 @@ all of your CSS. Below is an example PostCSS configuration file: ```js // postcss.config.js -const prefixer = require('postcss-prefix-selector'); +const prefixer = require("postcss-prefix-selector"); module.exports = { plugins: [ prefixer({ - prefix: "#single-spa-application\\:\\@org-name\\/project-name" - }) - ] -} + prefix: "#single-spa-application\\:\\@org-name\\/project-name", + }), + ], +}; ``` ### Shadow DOM @@ -214,7 +214,7 @@ To accomplish this, single-spa applications and parcels should remove `` a // This code is an example of the mechanics of mounting + unmounting + remounting CSS. // In practice, this is often done via tools like css-loader, style-loader, or // single-spa-css (rather than manually). -const style = document.createElement('style'); +const style = document.createElement("style"); style.textContent = `.settings {color: blue;}`; export const mount = [ @@ -222,14 +222,14 @@ export const mount = [ document.head.appendChild(styleElement); }, reactLifecycles.mount, -] +]; export const unmount = [ reactLifecycles.unmount, async () => { styleElement.remove(); - } -] + }, +]; ``` To help you accomplish this, this [single-spa-css](/docs/ecosystem-css#single-spa-css) library implements mount and unmount functions for you. diff --git a/versioned_docs/version-5.x/ecosystem-cycle.md b/versioned_docs/version-5.x/ecosystem-cycle.md index 96ba33533..5f2691911 100644 --- a/versioned_docs/version-5.x/ecosystem-cycle.md +++ b/versioned_docs/version-5.x/ecosystem-cycle.md @@ -7,24 +7,25 @@ sidebar_label: Cycle single-spa-cycle is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for for use with [Cycle.js](https://cycle.js.org/). Check out the [single-spa-cycle github](https://github.com/pcmnac/single-spa-cycle). ## Installation + ```sh npm install --save @pcmnac/single-spa-cycle ``` ## Quickstart + In your project's entry file, add the following: ```js - -import {run} from '@cycle/run' -import {makeDOMDriver} from '@cycle/dom' -import singleSpaCycle from '@pcmnac/single-spa-cycle'; -import rootComponent from './root.component.js'; +import { run } from "@cycle/run"; +import { makeDOMDriver } from "@cycle/dom"; +import singleSpaCycle from "@pcmnac/single-spa-cycle"; +import rootComponent from "./root.component.js"; const cycleLifecycles = singleSpaCycle({ run, rootComponent, - drivers: { DOM: makeDOMDriver(document.getElementById('main-content'))}, // or { DOM: makeDOMDriver('#main-content')} + drivers: { DOM: makeDOMDriver(document.getElementById("main-content")) }, // or { DOM: makeDOMDriver('#main-content')} }); export const bootstrap = cycleLifecycles.bootstrap; diff --git a/versioned_docs/version-5.x/ecosystem-dojo.md b/versioned_docs/version-5.x/ecosystem-dojo.md index 2e3c1359b..971146570 100644 --- a/versioned_docs/version-5.x/ecosystem-dojo.md +++ b/versioned_docs/version-5.x/ecosystem-dojo.md @@ -9,6 +9,7 @@ sidebar_label: Dojo single-spa-dojo is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for use with [Dojo](https://dojo.io/). Check out the [single-spa-dojo github](https://github.com/single-spa/single-spa-dojo). ## Installation + ```sh npm install --save single-spa-dojo @@ -17,13 +18,14 @@ yarn add single-spa-dojo ``` ## Quickstart + Your bundler's "entry file" should look like this, which allows your application to be downloaded as an in-browser ES module. ```js -import { renderer } from '@dojo/framework/core/vdom'; -import { v, w } from '@dojo/framework/widget-core/d'; -import singleSpaDojo from 'single-spa-dojo'; -import App from './app'; +import { renderer } from "@dojo/framework/core/vdom"; +import { v, w } from "@dojo/framework/widget-core/d"; +import singleSpaDojo from "single-spa-dojo"; +import App from "./app"; const dojoLifecycles = singleSpaDojo({ // required @@ -44,11 +46,11 @@ const dojoLifecycles = singleSpaDojo({ registry: myRegistry, // optional - one will be provided by single-spa automatically - domNode: document.getElementById('myContainer'), + domNode: document.getElementById("myContainer"), // optional - sync: true - } + sync: true, + }, }); export const bootstrap = dojoLifecycles.bootstrap; @@ -64,4 +66,4 @@ All options are passed to single-spa-dojo via the `opts` parameter when calling - `v` (required): The function used to render dom elements in Dojo. Often JSX hides this function from you, but it can be found at `import { v } from '@dojo/framework/widget-core/d'`. - `w` (required): The function used to render dom elements in Dojo. Often JSX hides this function from you, but it can be found at `import { w } from '@dojo/framework/widget-core/d'`. - `appComponent` (required): The class or function for your root Dojo component. -- `mountOptions` (optional): An object of [Dojo MountOptions](https://dojo.io/learn/creating-widgets/rendering-widgets#mountoptions-properties). Note that a `domNode` will be provided by single-spa-dojo, if one is not provided. \ No newline at end of file +- `mountOptions` (optional): An object of [Dojo MountOptions](https://dojo.io/learn/creating-widgets/rendering-widgets#mountoptions-properties). Note that a `domNode` will be provided by single-spa-dojo, if one is not provided. diff --git a/versioned_docs/version-5.x/ecosystem-ember.md b/versioned_docs/version-5.x/ecosystem-ember.md index e576e69eb..1a4c43158 100644 --- a/versioned_docs/version-5.x/ecosystem-ember.md +++ b/versioned_docs/version-5.x/ecosystem-ember.md @@ -9,6 +9,7 @@ single-spa-ember is a helper library that helps implement [single-spa registered It is available on npm as `single-spa-ember`, and also available on bower as `single-spa-ember` in case you want to use it with ember cli and need to use bower. ## Overview + When you are building an ember application that you want to work as a [single-spa application](https://github.com/single-spa/single-spa/blob/master/docs/applications.md#registered-applications), there are five things you need to implement: - A [loading function](https://github.com/single-spa/single-spa/blob/master/docs/root-application.md#loading-function) @@ -24,36 +25,44 @@ Note that the loading and activity functions are part of the [single-spa root ap ## API ### loadEmberApp + `loadEmberApp(appName, appUrl, vendorUrl)` is a function that helps you implement the [loading function](https://github.com/single-spa/single-spa/blob/master/docs/root-application.md#loading-function) for your ember application. `appName` and `appUrl` are both strings and both required, whereas `vendorUrl` is an optional string. ```js // In the single-spa root application -import {registerApplication} from 'single-spa'; -import {loadEmberApp} from 'single-spa-ember'; +import { registerApplication } from "single-spa"; +import { loadEmberApp } from "single-spa-ember"; -const name = 'ember-app'; -const app = () => loadEmberApp(name, '/dist/ember-app/assets/ember-app.js', '/dist/ember-app/assets/vendor.js'); -const activeWhen = location => location.hash.startsWith('ember'); +const name = "ember-app"; +const app = () => + loadEmberApp( + name, + "/dist/ember-app/assets/ember-app.js", + "/dist/ember-app/assets/vendor.js", + ); +const activeWhen = (location) => location.hash.startsWith("ember"); registerApplication({ name, app, activeWhen }); ``` ### singleSpaEmber + Single-spa-ember will implement the [single-spa lifecyle functions](https://github.com/single-spa/single-spa/blob/master/docs/applications.md#application-lifecycle) for you. To use it, you call the default export as a function with a configuration object, which returns an object that has `bootstrap`, `mount`, and `unmount` lifecycle functions on it. The provided configuration object has the following options: - - `App` (required): The [ember Application](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application). - - `createOpts` (optional): The options to provide when calling [App.create(options)](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application). See the [ember docs](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application) for more details. +- `App` (required): The [ember Application](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application). +- `createOpts` (optional): The options to provide when calling [App.create(options)](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application). See the [ember docs](https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application) for more details. ```js // In the ember application -import singleSpaEmber from 'single-spa-ember/src/single-spa-ember'; +import singleSpaEmber from "single-spa-ember/src/single-spa-ember"; const emberLifecycles = singleSpaEmber({ - appName: 'ember-app', // required - createOpts: { // See https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application - rootElement: '#ember-app', + appName: "ember-app", // required + createOpts: { + // See https://www.emberjs.com/api/ember/2.14.1/classes/Ember.Application + rootElement: "#ember-app", }, }); @@ -63,48 +72,45 @@ export const unmount = emberLifecycles.unmount; ``` ## Usage with ember cli + For the most part, you can get applications that use [ember cli](https://ember-cli.com/) to work pretty seamlessly with single-spa. Maybe the biggest thing you'll have to worry about is that ember-cli assumes that it controls the entire HTML page, whereas a single-spa application does not. However, usually we can achieve equivalent behavior by just loading the vendor and app bundles into the HTML page dynamically, instead of baking them right into the HTML page. Below is a description of the known things you should do when setting up an ember-cli application with single-spa: First, you'll need to add `single-spa-ember` as a dependency to the ember project. This can be done with `npm`, `yarn`, or `bower`. For example: - `npm init` - `npm install single-spa-ember` -or + or - `bower init` - `bower install single-spa-ember --save` Add the following options to your ember-cli-build.js file: + ```js /* eslint-env node */ -'use strict'; +"use strict"; -const EmberApp = require('ember-cli/lib/broccoli/ember-app'); +const EmberApp = require("ember-cli/lib/broccoli/ember-app"); -module.exports = function(defaults) { +module.exports = function (defaults) { let app = new EmberApp(defaults, { autoRun: false, // Set autoRun to false, because we only want the ember app to render to the DOM when single-spa tells it to. storeConfigInMeta: false, // We're making a single-spa application, which doesn't exclusively own the HTML file. So we don't want to have to have a `` tag for the ember environment to be initialized. - fingerprint: { - customHash: null, // This is optional, just will make it easier for you to have the same url every time you do an ember build. - }, + fingerprint: { + customHash: null, // This is optional, just will make it easier for you to have the same url every time you do an ember build. + }, // Add options here }); // Tell ember how to use the single-spa-ember library - pick one of the following // if you used npm or yarn - app.import('node_modules/single-spa-ember/amd/single-spa-ember.js', { - using: [ - {transformation: 'amd', as: 'single-spa-ember'}, - ], - }); + app.import("node_modules/single-spa-ember/amd/single-spa-ember.js", { + using: [{ transformation: "amd", as: "single-spa-ember" }], + }); // **or** if you used bower - app.import('bower_components/single-spa-ember/amd/single-spa-ember.js', { - using: [ - {transformation: 'amd', as: 'single-spa-ember'}, - ], - }); - + app.import("bower_components/single-spa-ember/amd/single-spa-ember.js", { + using: [{ transformation: "amd", as: "single-spa-ember" }], + }); return app.toTree(); }; @@ -114,21 +120,21 @@ In your single-spa root application (which is separate from anything generated b ```js // root-application.js -import * as singleSpa from 'single-spa'; -import {loadEmberApp} from 'single-spa-ember'; +import * as singleSpa from "single-spa"; +import { loadEmberApp } from "single-spa-ember"; -singleSpa.registerApplication('ember-app', loadingFunction, activityFunction); +singleSpa.registerApplication("ember-app", loadingFunction, activityFunction); function activityFunction(location) { // Only render the ember app when the url hash starts with ember - return location.hash.startsWith('ember'); + return location.hash.startsWith("ember"); } // single-spa-ember helps us load the script tags and give the ember app module to single-spa. function loadingFunction() { - const appName = 'ember-app'; - const appUrl = '/dist/ember-app/assets/ember-app.js'; - const vendorUrl = '/dist/ember-app/assets/vendor.js'; // Optional if you have one vendor bundle used for many different ember apps + const appName = "ember-app"; + const appUrl = "/dist/ember-app/assets/ember-app.js"; + const vendorUrl = "/dist/ember-app/assets/vendor.js"; // Optional if you have one vendor bundle used for many different ember apps return loadEmberApp(appName, appUrl, vendorUrl); } ``` @@ -137,17 +143,17 @@ In your app.js file (that is generated by ember cli) ```js // app.js (the ember application) -import Ember from 'ember'; -import Resolver from './resolver'; -import loadInitializers from 'ember-load-initializers'; -import config from './config/environment'; -import singleSpaEmber from 'single-spa-ember'; +import Ember from "ember"; +import Resolver from "./resolver"; +import loadInitializers from "ember-load-initializers"; +import config from "./config/environment"; +import singleSpaEmber from "single-spa-ember"; // This part is generated by the ember cli const App = Ember.Application.extend({ modulePrefix: config.modulePrefix, podModulePrefix: config.podModulePrefix, - Resolver + Resolver, }); loadInitializers(App, config.modulePrefix); @@ -156,12 +162,13 @@ export default App; // This is the single-spa part const emberLifecycles = singleSpaEmber({ - App, // required - appName: 'ember-app', // required - createOpts: { // optional - rootElement: '#ember-app', - }, -}) + App, // required + appName: "ember-app", // required + createOpts: { + // optional + rootElement: "#ember-app", + }, +}); // Single-spa lifecycles. export const bootstrap = emberLifecycles.bootstrap; diff --git a/versioned_docs/version-5.x/ecosystem-html-web-components.md b/versioned_docs/version-5.x/ecosystem-html-web-components.md index 4b4356223..4e54c2332 100644 --- a/versioned_docs/version-5.x/ecosystem-html-web-components.md +++ b/versioned_docs/version-5.x/ecosystem-html-web-components.md @@ -8,6 +8,7 @@ sidebar_label: HTML / Web Components single-spa applications or parcels. ## Installation + ```sh npm install --save single-spa-html @@ -16,6 +17,7 @@ yarn add single-spa-html ``` Alternatively, you can use single-spa-html from a CDN as a global variable: + ```html ``` @@ -24,14 +26,15 @@ Note that you might want to lock down the package to a specific version. See [he how to do that. ## Usage + ### Via npm ```js -import singleSpaHtml from 'single-spa-html'; +import singleSpaHtml from "single-spa-html"; const htmlLifecycles = singleSpaHtml({ - template: '', -}) + template: "", +}); export const bootstrap = htmlLifecycles.bootstrap; export const mount = htmlLifecycles.mount; @@ -39,22 +42,26 @@ export const unmount = htmlLifecycles.unmount; ``` ### Via cdn + Example usage when installed via CDN: ```js const webComponentApp = window.singleSpaHtml.default({ - template: props => ``, -}) + template: (props) => + ``, +}); singleSpa.registerApplication({ - name: 'name', + name: "name", app: webComponentApp, - activeWhen: () => true -}) + activeWhen: () => true, +}); ``` ## API / Options + single-spa-html is called with an object that has the following properties: + - `template` (required): An HTML string or a function that returns a string or promise that resolves a string. The function will be called with the single-spa custom props. The returned string is injected into the DOM during the single-spa mount lifecycle. - `domElementGetter` (optional): A function that is given the single-spa props and returns the dom element container into which the HTML will be injected. If omitted, a default implementation is provided that wraps the template in a `
` that is appended to `document.body`. diff --git a/versioned_docs/version-5.x/ecosystem-inferno.md b/versioned_docs/version-5.x/ecosystem-inferno.md index bfc26d1f9..02884ccee 100644 --- a/versioned_docs/version-5.x/ecosystem-inferno.md +++ b/versioned_docs/version-5.x/ecosystem-inferno.md @@ -11,15 +11,15 @@ single-spa-inferno is a helper library that helps implement [single-spa register First, in the application, run `npm install --save single-spa-inferno`. Then, add the following to your application's entry file. ```js -import Inferno from 'inferno'; -import rootComponent from './path-to-root-component.js'; -import singleSpaInferno from 'single-spa-inferno'; +import Inferno from "inferno"; +import rootComponent from "./path-to-root-component.js"; +import singleSpaInferno from "single-spa-inferno"; const infernoLifecycles = singleSpaInferno({ Inferno, createElement, rootComponent, - domElementGetter: () => document.getElementById('main-content'), + domElementGetter: () => document.getElementById("main-content"), }); export const bootstrap = infernoLifecyles.bootstrap; @@ -34,4 +34,4 @@ All options are passed to single-spa-inferno via the `opts` parameter when calli - `inferno`: (required) The main Inferno object, which is generally either exposed onto the window or is available via `require('inferno')` or `import Inferno from 'inferno'`. - `createElement`: (required) The default export from Inferno's `inferno-create-element` package. - `rootComponent`: (required) The top level Inferno component which will be rendered. -- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Inferno application will be bootstrapped, mounted, and unmounted. \ No newline at end of file +- `domElementGetter`: (required) A function that takes in no arguments and returns a DOMElement. This dom element is where the Inferno application will be bootstrapped, mounted, and unmounted. diff --git a/versioned_docs/version-5.x/ecosystem-leaked-globals.md b/versioned_docs/version-5.x/ecosystem-leaked-globals.md index d4f7a83ea..5370b2f75 100644 --- a/versioned_docs/version-5.x/ecosystem-leaked-globals.md +++ b/versioned_docs/version-5.x/ecosystem-leaked-globals.md @@ -9,33 +9,38 @@ that depend on global variables. Such applications are usually applications that that were popular when ES modules were not yet available. ## What single-spa-leaked-globals does + single-spa-leaked-globals will remove specific global variables from `window` during your application's [unmount lifecycle](/docs/building-applications#unmount), and add them back to `window` during your application's [mount lifecycle](/docs/building-applications#mount). ## Before using single-spa-leaked-globals + It might be okay for single-spa applications to leak some global variables. Those leaked global variables could be harmless. Below are some situations where using single-spa-leaked-globals could be useful. If your situation is not listed, consider not using single-spa-leaked-globals. 1. Your applications are accidentally sharing global variables and the order in which they are mounted matters. For example, the jQuery `$` variable - is available at the start, but app1 installs a jQuery plugin that app2 assumes is there. If app2 is mounted - before app1, you might get an error because the jQuery plugin is not installed. In that situation, the best solution is maybe to install - the jQuery plugin inside of your [single-spa config](/docs/configuration). But if that's not desireable, you can use single-spa-leaked-globals - to manage two separate versions of jQuery -- one for app1 and one for app2. + is available at the start, but app1 installs a jQuery plugin that app2 assumes is there. If app2 is mounted + before app1, you might get an error because the jQuery plugin is not installed. In that situation, the best solution is maybe to install + the jQuery plugin inside of your [single-spa config](/docs/configuration). But if that's not desireable, you can use single-spa-leaked-globals + to manage two separate versions of jQuery -- one for app1 and one for app2. 2. Your applications require different versions of the same global variable. For example, consider when app1 depends on - an [underscorejs](https://underscorejs.org/) `_` global variable and app2 depends on a [lodash](https://lodash.com/) `_` global variable. - They both need a global `_` variable, but expect different functions to be available on it. The same could be true for different versions of the - same library, such as lodash 3 vs lodash 4. In those situations, you can use single-spa-leaked-globals to make sure the `_` that is available - for app1 and app2 is the correct one. + an [underscorejs](https://underscorejs.org/) `_` global variable and app2 depends on a [lodash](https://lodash.com/) `_` global variable. + They both need a global `_` variable, but expect different functions to be available on it. The same could be true for different versions of the + same library, such as lodash 3 vs lodash 4. In those situations, you can use single-spa-leaked-globals to make sure the `_` that is available + for app1 and app2 is the correct one. ## Limitations + single-spa-leaked-globals cannot change the global nature of global dependencies. Only one instance of the global variable can be on the `window` at a time. **This means that you probably can only have one application mounted at a time that depends on that global variable.** If two applications depend on the same global variable and are [active](/docs/configuration#activity-function) at the same time, single-spa-leaked-globals won't work for you. ## Installation + ### Via npm + ```sh npm install --save single-spa-leaked-globals @@ -44,15 +49,18 @@ yarn add single-spa-leaked-globals ``` ### Via cdn + You can also use single-spa-leaked-globals via CDN, ironically as a global variable itself: + ```html ``` -Note that you should probably lock down the version of the library to avoid accidentally upgrading. See +Note that you should probably lock down the version of the library to avoid accidentally upgrading. See https://cdn.jsdelivr.net/npm/single-spa-leaked-globals/ to find the latest version. ## Usage + The single-spa-leaked-globals library is often used in conjunction with another helper library, such as single-spa-angularjs or single-spa-backbone. As such, you'll want to [export an array](/docs/building-applications#registered-application-lifecycle) for your lifecycle functions @@ -89,13 +97,16 @@ export const unmount = [ ``` If you're using single-spa-leaked-globals as a global variable itself: + ```js const leakedGlobalsLifecycles = window.singleSpaLeakedGlobals.default({ - globalVariableNames: ['_'], -}) + globalVariableNames: ["_"], +}); ``` ## API / Options + single-spa-leaked-globals is called with an object with the following properties: + - `globalVariableNames` (required): An array of strings. Each string is the name of a global variable that should be removed when the application is unmounted, and added back when the application is mounted. diff --git a/versioned_docs/version-5.x/ecosystem-preact.md b/versioned_docs/version-5.x/ecosystem-preact.md index 4ffb528f3..dd52e03cd 100644 --- a/versioned_docs/version-5.x/ecosystem-preact.md +++ b/versioned_docs/version-5.x/ecosystem-preact.md @@ -7,22 +7,24 @@ sidebar_label: Preact single-spa-preact is a helper library that helps implement [single-spa registered application](configuration#registering-applications) [lifecycle functions](building-applications.md#registered-application-lifecycle) (bootstrap, mount and unmount) for for use with [Preact](https://preactjs.com/). Check out the [single-spa-preact github](https://github.com/single-spa/single-spa-preact). ## Installation + ```sh npm install --save preact ``` ## Quickstart + In your project's entry file, add the following: ```js -import preact from 'preact'; -import rootComponent from './path-to-root-component.js'; -import singleSpaPreact from 'single-spa-preact'; +import preact from "preact"; +import rootComponent from "./path-to-root-component.js"; +import singleSpaPreact from "single-spa-preact"; const preactLifecycles = singleSpaPreact({ preact, rootComponent, - domElementGetter: () => document.getElementById('main-content'), + domElementGetter: () => document.getElementById("main-content"), }); export const bootstrap = preactLifecycles.bootstrap; diff --git a/versioned_docs/version-5.x/ecosystem-react.md b/versioned_docs/version-5.x/ecosystem-react.md index f77a9a420..cc4c00c80 100644 --- a/versioned_docs/version-5.x/ecosystem-react.md +++ b/versioned_docs/version-5.x/ecosystem-react.md @@ -24,11 +24,11 @@ Alternatively, you can use single-spa-react by adding ` ``` @@ -181,8 +180,8 @@ Sharing a single instance of Vue and other common libraries is highly recommende ```js // vue.config.js module.exports = { - chainWebpack: config => { - config.externals(['vue', 'vue-router']); + chainWebpack: (config) => { + config.externals(["vue", "vue-router"]); }, }; ``` @@ -192,7 +191,7 @@ module.exports = { ```js // webpack.config.js module.exports = { - externals: ['vue', 'vue-router'], + externals: ["vue", "vue-router"], }; ``` @@ -203,7 +202,7 @@ All options are passed to single-spa-vue via the `opts` parameter when calling ` - `Vue`: (required) The main Vue object, which is generally either exposed onto the window or is available via `require('vue')` `import Vue from 'vue'`. - `appOptions`: (required) An object or async function which will be used to instantiate your Vue.js application. `appOptions` will pass directly through to `new Vue(appOptions)`. Note that if you do not provide an `el` to appOptions, that a div will be created and appended to the DOM as a default container for your Vue application. When `appOptions` is an async function, it receives the single-spa props as an argument (as of single-spa-vue@2.4.0). - `loadRootComponent`: (optional and replaces `appOptions.render`) A promise that resolves with your root component. This is useful for lazy loading. -- `handleInstance`: (optional) A method can be used to handle Vue instance. Vue 3 brings [new instance API](https://v3.vuejs.org/guide/migration/global-api.html#a-new-global-api-createapp), and you can access *the app instance* from this, like `handleInstance: (app, props) => app.use(router)`. For Vue 2 users, a [Vue instance](https://vuejs.org/v2/guide/instance.html) can be accessed. The `handleInstance(app, props)` function receives the instance as its first argument, and single-spa props as its second argument. If handleInstance returns a promise, single-spa-vue will wait to resolve the app / parcel's `mount` lifecycle until the handleInstance promise resolves. +- `handleInstance`: (optional) A method can be used to handle Vue instance. Vue 3 brings [new instance API](https://v3.vuejs.org/guide/migration/global-api.html#a-new-global-api-createapp), and you can access _the app instance_ from this, like `handleInstance: (app, props) => app.use(router)`. For Vue 2 users, a [Vue instance](https://vuejs.org/v2/guide/instance.html) can be accessed. The `handleInstance(app, props)` function receives the instance as its first argument, and single-spa props as its second argument. If handleInstance returns a promise, single-spa-vue will wait to resolve the app / parcel's `mount` lifecycle until the handleInstance promise resolves. - `replaceMode`: (optional, defaults to `false`) A boolean that determines whether your root Vue component will entirely replace the container element it's mounted to. The Vue library always replaces, so to implement `replaceMode: false` a temporary `
` element is created inside of the container, so that Vue replaces that element rather than the container. Introduced in single-spa-vue@2.3.0. To configure which dom element the single-spa application is mounted to, use [appOptions.el](https://vuejs.org/v2/api/#el): @@ -212,8 +211,8 @@ To configure which dom element the single-spa application is mounted to, use [ap const vueLifecycles = singleSpaVue({ Vue, appOptions: { - render: h => h(App), - el: '#a-special-container', + render: (h) => h(App), + el: "#a-special-container", }, }); ``` @@ -226,8 +225,8 @@ const vueLifecycles = singleSpaVue({ async appOptions() { return { router: await routerFactory(), - render: h => h(App) - } + render: (h) => h(App), + }; }, }); ``` @@ -394,10 +393,10 @@ With this directory structure (which is the Vue CLI default), the public path sh // vue.config.js module.exports = { chainWebpack(config) { - config.plugin('SystemJSPublicPathWebpackPlugin').tap((args) => { + config.plugin("SystemJSPublicPathWebpackPlugin").tap((args) => { args[0].rootDirectoryLevel = 1; return args; }); - } -} + }, +}; ``` diff --git a/versioned_docs/version-5.x/ecosystem.md b/versioned_docs/version-5.x/ecosystem.md index 6c7c42bfa..7bf8d96bb 100644 --- a/versioned_docs/version-5.x/ecosystem.md +++ b/versioned_docs/version-5.x/ecosystem.md @@ -7,6 +7,7 @@ sidebar_label: Overview The single-spa ecosystem is quickly growing to support as many frameworks and build tools as possible. ## Help for frameworks + There is a growing number of projects that help you bootstrap, mount, and unmount your applications that are written with popular frameworks. Feel free to contribute to this list with your own project: diff --git a/versioned_docs/version-5.x/faq.md b/versioned_docs/version-5.x/faq.md index 04c37b2b5..a8a8d6dd0 100644 --- a/versioned_docs/version-5.x/faq.md +++ b/versioned_docs/version-5.x/faq.md @@ -140,9 +140,9 @@ Single spa supports code splits. There are so many ways to code split we won't b - For SystemJS >= 6, use [systemjs-webpack-interop](https://github.com/joeldenning/systemjs-webpack-interop): ```js - import { setPublicPath } from 'systemjs-webpack-interop'; + import { setPublicPath } from "systemjs-webpack-interop"; - setPublicPath('name-of-module-in-import-map'); + setPublicPath("name-of-module-in-import-map"); ``` - For SystemJS 2-5: Find a code example [here](https://gitlab.com/TheMcMurder/single-spa-portal-example/blob/master/people/src/set-public-path.js#L3) diff --git a/versioned_docs/version-5.x/layout-api.md b/versioned_docs/version-5.x/layout-api.md index 8ea20b9d6..d31a62e51 100644 --- a/versioned_docs/version-5.x/layout-api.md +++ b/versioned_docs/version-5.x/layout-api.md @@ -134,10 +134,10 @@ In NodeJS, single-spa-layout exports the following functions as named exports. N ```js // Works in newer versions of NodeJS -import 'single-spa-layout'; +import "single-spa-layout"; // Works in older versions of NodeJS -import 'single-spa-layout/dist/esm/single-spa-layout-server.min.js'; +import "single-spa-layout/dist/esm/single-spa-layout-server.min.js"; ``` ### constructServerLayout @@ -145,13 +145,13 @@ import 'single-spa-layout/dist/esm/single-spa-layout-server.min.js'; 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. ```js -import { constructServerLayout } from 'single-spa-layout/server'; +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" -}) + filePath: "server/views/index.html", +}); // Alternatively, provide the html as a string const serverLayout = constructServerLayout({ @@ -163,8 +163,8 @@ const serverLayout = constructServerLayout({ - ` -}) + `, +}); ``` **Arguments** diff --git a/versioned_docs/version-5.x/layout-definition.md b/versioned_docs/version-5.x/layout-definition.md index 610595eed..f56ea49ee 100644 --- a/versioned_docs/version-5.x/layout-definition.md +++ b/versioned_docs/version-5.x/layout-definition.md @@ -50,7 +50,7 @@ const routes = constructRoutes(` ```js // With a properly configured bundler, you can import the html as a string from another file -import layout from './microfrontends-layout.html'; +import layout from "./microfrontends-layout.html"; const routes = constructRoutes(layout); ``` @@ -61,11 +61,13 @@ You may define your layout as JSON, including routes, applications, and arbitrar ```js const routes = constructRoutes({ - "routes": [ - { "type": "route", "path": "settings", "routes": [ - { "type": "application", "name": "settings" } - ]} - ] + routes: [ + { + type: "route", + path: "settings", + routes: [{ type: "application", name: "settings" }], + }, + ], }); ``` @@ -98,7 +100,11 @@ Note that `