Standalone single-spa webpack plugin

raw JSON →
6.0.0 verified Sat Apr 25 auth: no javascript

A webpack plugin that enables running single-spa microfrontends in standalone mode for development, as an alternative to import-map-overrides. Current stable version is 6.0.0, released with breaking changes: moduleFormat now defaults to ESM instead of SystemJS, and HtmlWebpackPlugin option is now required. The plugin rewrites the microfrontend's HTML and JS to load and mount it as a standalone single-spa application or parcel, with support for import maps, custom props, and start options. It ships TypeScript types and requires webpack and html-webpack-plugin as peer dependencies. Key differentiators: built specifically for single-spa ecosystem, supports ESM and SystemJS module formats, integrates with import-map-overrides UI, and provides a local development experience that simulates the microfrontend being part of a larger single-spa application. However, it is not equivalent to integrated mode and has known pitfalls such as updated single-spa/SystemJS versions and missing global styles/scripts.

error Error: The standalone-single-spa-webpack-plugin requires HtmlWebpackPlugin to be added to the plugins array before it.
cause HtmlWebpackPlugin plugin is missing or placed after StandaloneSingleSpaPlugin in the webpack config plugins array.
fix
Ensure new HtmlWebpackPlugin() is added before new StandaloneSingleSpaPlugin(...) in the plugins array.
error Module not found: Error: Can't resolve 'single-spa'
cause single-spa is not installed or not available in node_modules during webpack compilation.
fix
Install single-spa: npm install single-spa
error Error: StandaloneSingleSpaPlugin is not a constructor
cause Misimported the plugin (e.g., named import instead of default import in CommonJS).
fix
Use const StandaloneSingleSpaPlugin = require('standalone-single-spa-webpack-plugin');
error TypeError: Cannot read properties of undefined (reading 'tap')
cause HtmlWebpackPlugin is not properly instantiated or not passed to StandaloneSingleSpaPlugin options.
fix
Ensure new HtmlWebpackPlugin() is added to plugins and/or pass the HtmlWebpackPlugin constructor as an option to StandaloneSingleSpaPlugin.
breaking moduleFormat now defaults to ESM rather than SystemJS in v6
fix If your project depends on SystemJS, set moduleFormat: 'systemjs' explicitly.
breaking HtmlWebpackPlugin option is now required in v6
fix Add new HtmlWebpackPlugin() to plugins array and ensure it runs before StandaloneSingleSpaPlugin.
breaking html-webpack-plugin@3 is no longer supported in v5
fix Upgrade html-webpack-plugin to version 4 or later.
deprecated urlRerouteOnly default changed to true in v3
fix If you need urlRerouteOnly: false, set startOptions: { urlRerouteOnly: false }.
gotcha Standalone mode is not equivalent to integrated mode; root config differences may cause issues
fix Always test in the full single-spa integration environment. Use import-map-overrides for more accurate local development.
gotcha Plugin automatically upgrades to latest SystemJS and single-spa versions, which may differ from production
fix Pin standalone plugin version or use a custom import map to control versions.
gotcha No global scripts, fonts, or CSS are loaded by default in standalone mode
fix Manually add required global resources via html-webpack-plugin or a custom template.
npm install standalone-single-spa-webpack-plugin
yarn add standalone-single-spa-webpack-plugin
pnpm add standalone-single-spa-webpack-plugin

Adds the standalone plugin to webpack config with HtmlWebpackPlugin, enabling development of a single-spa microfrontend in standalone mode.

// webpack.config.js
const StandaloneSingleSpaPlugin = require('standalone-single-spa-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin(),
    new StandaloneSingleSpaPlugin({
      appOrParcelName: 'my-app',
      moduleFormat: 'esm', // defaults to 'esm' in v6
      activeWhen: ['/'],
      importMapOverrides: true,
    }),
  ],
  devServer: {
    historyApiFallback: true,
  },
};