Version: 5.x

create-single-spa

Single-spa offers a CLI for those who prefer autogenerated and managed configurations for webpack, babel, jest, etc. You do not have to use the CLI in order to use single-spa.

The CLI is called create-single-spa (Github link). It is primarily intended for the creation of new projects, but may also be useful for migrating existing projects (especially migrating CRA or frameworkless projects).

If you wish to have create-single-spa globally available, run the following in a terminal

  1. npm install --global create-single-spa
  2. # or
  3. yarn global add create-single-spa

Then run the following:

  1. create-single-spa

Alternatively, you may use create-single-spa without global installation:

  1. npm init single-spa
  2. # or
  3. npx create-single-spa
  4. # or
  5. yarn create single-spa

This will open up a CLI prompt asking you what kind of project you want to create or update.

You may pass arguments to create-single-spa like so:

  1. # Different ways of doing the same thing
  2. create-single-spa --framework react
  3. npm init single-spa --framework react
  4. npx create-single-spa --framework react
  5. yarn create single-spa --framework react

Here are the available CLI options:

You may specify which directory create-single-spa runs in through either of the following ways:

  1. # Two ways of doing the same thing
  2. create-single-spa my-dir
  3. create-single-spa --dir my-dir

You can specify which kind of microfrontend you are creating with the --moduleType CLI argument:

  1. create-single-spa --moduleType root-config
  2. create-single-spa --moduleType app-parcel
  3. create-single-spa --moduleType util-module

You can specify which framework you’re using with the --framework CLI argument. Note that if you specify a framework that you may omit the --moduleType, as it is inferred to be app-parcel.

  1. create-single-spa --framework react
  2. create-single-spa --framework vue
  3. create-single-spa --framework angular

When generating a root config, the --layout CLI argument indicates that you want to use single-spa-layout in your root config.

This option skips npm/yarn/pnpm installation during project creation.

create-single-spa asks you if you’d like to create a single-spa application, a utility module, or a root-config. All three module types assume that you are using the recommended setup.

If you select that you’d like to create a single-spa application, you will be prompted for which framework you’d like to choose. React is implemented with premade configurations for babel + webpack + jest. Angular is implemented with Angular CLI and single-spa-angular. Vue is implemented with Vue CLI and vue-cli-plugin-single-spa.

NPM packages

Within the create-single-spa repo, there are several NPM packages. The following sections document each package:

Github project

The core CLI, which invokes generator-single-spa.

Github project

A Yeoman generator that prompts the user and then creates files. This is primarily invoked via the create-single-spa CLI, but can also be composed if you’d like to customize it.

Github project

A shareable, customizable webpack config that is used for utility modules and single-spa applications.

  1. npm install --save-dev webpack-config-single-spa webpack-merge
  2. # or
  3. yarn add --dev webpack-config-single-spa webpack-merge
  1. const webpackMerge = require('webpack-merge');
  2. const singleSpaDefaults = require('webpack-config-single-spa');
  3. module.exports = (webpackConfigEnv, argv) => {
  4. const defaultConfig = singleSpaDefaults({
  5. // The name of the organization this application is written for
  6. orgName: 'name-of-company',
  7. // The name of the current project. This usually matches the git repo's name
  8. projectName: 'name-of-project',
  9. // See https://webpack.js.org/guides/environment-variables/#root for explanation of webpackConfigEnv
  10. webpackConfigEnv,
  11. // The CLI commands in the package.json script that triggered this build
  12. argv,
  13. // optional
  14. // This changes whether package names that start with @your-org-name are
  15. // treated as webpack externals or not. Defaults to true
  16. orgPackagesAsExternal: true,
  17. // optional, defaults to 1
  18. // This is the rootDirectoryLevel that is passed to https://github.com/joeldenning/systemjs-webpack-interop
  19. rootDirectoryLevel: 1,
  20. // optional, defaults to false
  21. // Disable html-webpack-plugin (and standalone-single-spa-webpack-plugin) entirely
  22. // This is intended for root configs, but can be used in other cases, too
  23. disableHtmlGeneration: false
  24. });
  25. return webpackMerge.smart(defaultConfig, {
  26. // modify the webpack config however you'd like to by adding to this object
  27. });
  28. };

Github project

A shareable, customizable webpack config that adds react-specific configuration to webpack-config-single-spa.

  1. npm install --save-dev webpack-config-single-spa-react webpack-merge
  2. # or
  3. yarn add --dev webpack-config-single-spa-react webpack-merge
  1. const webpackMerge = require('webpack-merge');
  2. const singleSpaDefaults = require('webpack-config-single-spa-react');
  3. module.exports = (webpackConfigEnv, argv) => {
  4. const defaultConfig = singleSpaDefaults({
  5. // The name of the organization this application is written for
  6. orgName: 'name-of-company',
  7. // The name of the current project. This usually matches the git repo's name
  8. projectName: 'name-of-project',
  9. // See https://webpack.js.org/guides/environment-variables/#root for explanation of webpackConfigEnv
  10. webpackConfigEnv,
  11. // The CLI commands in the package.json script that triggered this build
  12. argv,
  13. // optional
  14. // This changes whether package names that start with @your-org-name are
  15. // treated as webpack externals or not. Defaults to true
  16. orgPackagesAsExternal: true,
  17. // optional, defaults to 1
  18. // This is the rootDirectoryLevel that is passed to https://github.com/joeldenning/systemjs-webpack-interop
  19. rootDirectoryLevel: 1,
  20. // optional, defaults to {}
  21. // This controls the options given to standalone-single-spa-webpack-plugin
  22. // See https://github.com/single-spa/standalone-single-spa-webpack-plugin#usage
  23. standaloneOptions: {
  24. }
  25. });
  26. return webpackMerge.smart(defaultConfig, {
  27. // modify the webpack config however you'd like to by adding to this object
  28. });
  29. };

Github project

A shareable, customizable webpack config that adds typescript-specific configuration to webpack-config-single-spa. Note that webpack-config-single-spa-ts has a peerDependency on typescript.

  1. npm install --save-dev webpack-config-single-spa-ts webpack-merge
  2. # or
  3. yarn add --dev webpack-config-single-spa-ts webpack-merge
  1. const webpackMerge = require('webpack-merge');
  2. const singleSpaDefaults = require('webpack-config-single-spa-ts');
  3. module.exports = (webpackConfigEnv, argv) => {
  4. const defaultConfig = singleSpaDefaults({
  5. // The name of the organization this application is written for
  6. orgName: 'name-of-company',
  7. // The name of the current project. This usually matches the git repo's name
  8. projectName: 'name-of-project',
  9. // See https://webpack.js.org/guides/environment-variables/#root for explanation of webpackConfigEnv
  10. webpackConfigEnv,
  11. // The CLI commands in the package.json script that triggered this build
  12. argv,
  13. });
  14. return webpackMerge.smart(defaultConfig, {
  15. // modify the webpack config however you'd like to by adding to this object
  16. });
  17. };
  1. const singleSpaTs = require('webpack-config-single-spa-ts');
  2. // Alternatively, you may modify a webpack config directly
  3. const myOtherWebpackConfig = {
  4. /* ... */
  5. };
  6. const finalConfig = singleSpaDefaults.modifyConfig(myOtherWebpackConfig);

Github project

A shareable, customizable webpack config that creates a webpack config that works with both react and typescript. Note that webpack-config-single-spa-react-ts simply merges the config from webpack-config-single-spa-react with that of webpack-config-single-spa-ts.

  1. npm install --save-dev webpack-config-single-spa-react-ts webpack-merge
  2. # or
  3. yarn add --dev webpack-config-single-spa-react-ts webpack-merge
  1. const webpackMerge = require('webpack-merge');
  2. const singleSpaDefaults = require('webpack-config-single-spa-react-ts');
  3. module.exports = (webpackConfigEnv, argv) => {
  4. const defaultConfig = singleSpaDefaults({
  5. // The name of the organization this application is written for
  6. orgName: 'name-of-company',
  7. // The name of the current project. This usually matches the git repo's name
  8. projectName: 'name-of-project',
  9. // optional
  10. // This changes whether package names that start with @your-org-name are
  11. // treated as webpack externals or not. Defaults to true
  12. orgPackagesAsExternal: true,
  13. // See https://webpack.js.org/guides/environment-variables/#root for explanation of webpackConfigEnv
  14. webpackConfigEnv,
  15. // The CLI commands in the package.json script that triggered this build
  16. argv,
  17. // optional, defaults to 1
  18. // This is the rootDirectoryLevel that is passed to https://github.com/joeldenning/systemjs-webpack-interop
  19. rootDirectoryLevel: 1,
  20. // optional, defaults to false.
  21. // When true, this removes html-webpack-plugin and standalone-single-spa-webpack-plugin
  22. disableHtmlGeneration: false
  23. })
  24. return webpackMerge.smart(defaultConfig, {
  25. // modify the webpack config however you'd like to by adding to this object
  26. })
  27. }

The single-spa-web-server-utils package is a collection of functions that help when implementing a web server for an index.html file. This package can be used to inline import maps into an HTML, which helps with the performance of your application. Additionally, it can be used to modify a browser import map so that it’s suitable for usage in NodeJS for dynamic module loading and server rendering (Dynamic Module Loading and Server Rendering)).

The web server utils poll the import map from a URL and generate a browserImportMap and nodeImportMap from the response.

  1. npm install --save single-spa-web-server-utils
  2. # alternatively
  3. yarn add single-spa-web-server-utils

The getImportMaps function accepts an object parameter and returns a promise that resolves with an object with two import maps: browserImportMap and nodeImportMap. Note that import maps are polled at the specified interval forever until either reset() or clearAllIntervals() is called. Import Maps are stored in memory in a javascript variable that exists outside of the getImportMaps function, so subsequent calls to getImportMaps will all use the same cache.

  1. const { getImportMaps } = require('single-spa-web-server-utils');
  2. const http = require('http');
  3. const ejs = require('ejs');
  4. const fs = require('fs');
  5. const path = require('path');
  6. const htmlTemplate = ejs.compile(
  7. fs.readFileSync(path.resolve(process.cwd(), 'views/index.html'), 'utf-8'),
  8. );
  9. http.createServer((req, res) => {
  10. getImportMaps({
  11. // required
  12. // The URL at which the server
  13. url: 'https://my-cdn.com/live.importmap',
  14. // optional - defaults to 30000
  15. // The ms to wait when polling the import map
  16. pollInterval: 30000,
  17. // optional - defaults to false
  18. // Whether to allow for import-map-overrides via cookies sent in the request.
  19. // More details about overrides via cookies at
  20. // https://github.com/joeldenning/import-map-overrides/blob/master/docs/api.md#node
  21. allowOverrides: true,
  22. // optional - only needed when allowOverrides is true
  23. // The IncomingMessage from an http server. This is used to gather
  24. // cookies for import-map-overrides
  25. req,
  26. // optional
  27. // This allows you to remove entries from the downloaded import map
  28. // from the returned `nodeImportMap`. This is useful for customizing
  29. // an import map that is used in the browser so that it can be used
  30. // for dynamic NodeJS module loading. Each key is a string import specifier.
  31. // Keys that you return `true` for are preserved in the nodeImportMap.
  32. nodeKeyFilter(key) {
  33. return true;
  34. },
  35. }).then(({ browserImportMap, nodeImportMap }) => {
  36. console.log(browserImportMap, nodeImportMap);
  37. // Example of how to inline a browser import map
  38. const htmlWithInlinedImportMap = htmlTemplate({
  39. importMap: browserImportMap,
  40. });
  41. res.setResponseHeader('Content-Type', 'text/html');
  42. res.status(200).send(htmlWithInlinedImportMap);
  43. // Example of how to apply a NodeJS import map
  44. // More info at https://github.com/node-loader/node-loader-import-maps
  45. global.nodeLoader.setImportMapPromise(Promise.resolve(nodeImportMap));
  46. import('module-in-import-map');
  47. });
  48. });

This clears all import map polling intervals that were created via setInterval() inside of getImportMaps(). This is useful for tests and for cleaning up memory.

  1. import { clearAllIntervals } from 'single-spa-web-server-utils';
  2. clearAllIntervals();

This clears all intervals (see clearAllIntervals), and also clears the in-memory cache of all import maps. In other words, after reset() is called, getImportMaps() will always result in a new network request to fetch the import map.

  1. import { reset } from 'single-spa-web-server-utils';
  2. reset();

The create-single-spa CLI internally uses webpack-merge to merge together webpack configs. Additionally, the CLI generates a webpack.config.js file in each project where you can customize the webpack config further via webpack-merge.

When merging webpack rules, use webpack-merge’s mergeWithRules function to avoid duplicate rules.

Example

webpack-config-single-spa and its variants often depend on webpack loaders. Because webpack loaders are loaded via file path, it’s possible to accidentally have duplicate copies of the same loader, if the same loader is also installed in both webpack-config-single-spa and in your project. This can result in errors.

To avoid duplicate copies of loaders, first check whether it is already installed by wepback-config-single-spa before adding it to your own project (see package.json). If the loader is listed there, then do not install it into your project, too. If you already have the loader installed in your project, uninstall it.

When referencing a loader that is installed as a dependency of webpack-config-single-spa, use require.resolve to ensure the loader is imported from the correct path:

  1. const { mergeWithRules } = require('webpack-merge');
  2. const singleSpaDefaults = require('webpack-config-single-spa');
  3. module.exports = (webpackConfigEnv) => {
  4. const defaultConfig = singleSpaDefaults({
  5. orgName: "react-mf",
  6. projectName: "styleguide",
  7. webpackConfigEnv,
  8. });
  9. return mergeWithRules({
  10. module: {
  11. rules: {
  12. test: "match",
  13. use: "replace",
  14. },
  15. },
  16. })(defaultConfig, {
  17. module: {
  18. rules: [
  19. {
  20. test: /\.css$/i,
  21. use: [
  22. // Use require.resolve to ensure the correct loader is used
  23. require.resolve("style-loader", {
  24. paths: [require.resolve("webpack-config-single-spa")],
  25. }),
  26. require.resolve("css-loader", {
  27. paths: [require.resolve("webpack-config-single-spa")],
  28. }),
  29. "postcss-loader",
  30. ],
  31. },
  32. ],
  33. },
  34. })
  35. }

create-single-spa - 图1Edit this page