npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

single-spa-login-example-with-npm-packages

v0.2.4

Published

Single-spa application example which imports registered applications from NPM packages and manages authentication features as login.

Downloads

8

Readme

npm version

single-spa-login-example-with-npm-packages

Single-spa application example which imports registered applications from NPM packages and manages authentication features as login.

✍🏻 Motivation

This application is a little demo of how you can use single-spa splitting code with Option 2: NPM packages

▶️ Demo

You can see a working demo of this application in the next link: https://single-spa-with-npm-packages.herokuapp.com.

The login validation is harcoded in code and the credentials are:

| User | Password |
| ------------- |:-------------:| | admin | 12345 |

💻 Run in localhost

If you prefer run this application in localhost you must follow next steps:

npm install
npm run serve

Finally you only have to open http://localhost:8080 in a browser to see the app running

single-spa applications

This application is a root-application that inits a single-spa application that integrates several registered applications:

single-spa-auth-app

This application is displayed by default as there is no logged in user. A login form is printed and the credentials can be set for perform the login and access to the private views.

single-spa-layout-app

This application contains header, navbar and footer sections, navigation between registered applications and /login redirection if logout link is clicked or token is removed from sessionStorage.

single-spa-home-app

This application is developed with Angular JS and is mounted when home icon in navbar is clicked. In that case the url will be / and all Angular JS routes will be managed by angular-ui-router. By the moment this application has only one default routed view.

single-spa-angular-app

This application is developed with Angular v8 and is mounted when Angular navbar item is clicked. In that case the url will be /angular and all Angular routes will be managed by angular router.

single-spa-vue-app

This application is developed with Vue and is mounted when Vue navbar item is clicked. In that case the url will be /vue and all Vue routes will be managed by vue-router.

single-spa-react-app

This application is developed with React and is mounted when React navbar item is clicked. In that case the url will be /react and all React routes will be managed by react-router-dom.

How it works ❓

There are several files for the right working of this application and they are:

  • package.json
  • root-application.js
  • server.js
  • webpack.config.js

package.json

{
  "name": "single-spa-login-example-with-npm-packages",
  "version": "0.2.4",
  "description": "Single-spa application example which imports registered applications from NPM packages and manages authentication features as login.",
  "main": "root-application.js",
  "scripts": {
    "serve": "webpack-dev-server",
    "start": "node server.js",
    "build": "webpack --config webpack.config.js -p",
    "heroku-postbuild": "npm run build",
    "lint": "eslint . --ext .js --fix",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/jualoppaz/single-spa-login-example-with-npm-packages.git"
  },
  "author": "Juan Manuel López Pazos",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/jualoppaz/single-spa-login-example-with-npm-packages/issues"
  },
  "homepage": "https://github.com/jualoppaz/single-spa-login-example-with-npm-packages#readme",
  "devDependencies": {
    "@babel/core": "7.8.3",
    "babel-eslint": "10.0.3",
    "babel-loader": "8.0.6",
    "clean-webpack-plugin": "3.0.0",
    "copy-webpack-plugin": "5.1.1",
    "css-loader": "3.4.2",
    "eslint": "6.8.0",
    "eslint-config-airbnb-base": "14.0.0",
    "eslint-loader": "3.0.3",
    "eslint-plugin-import": "2.20.1",
    "html-webpack-plugin": "3.2.0",
    "webpack": "4.41.5",
    "webpack-cli": "3.3.10",
    "webpack-dev-server": "3.11.0"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "1.2.27",
    "@fortawesome/free-brands-svg-icons": "5.12.1",
    "@fortawesome/free-solid-svg-icons": "5.12.0",
    "@fortawesome/vue-fontawesome": "0.1.9",
    "bootstrap": "4.4.1",
    "bootstrap-vue": "2.2.2",
    "single-spa": "4.4.2",
    "single-spa-angular-app": "0.1.5",
    "single-spa-auth-app": "0.1.4",
    "single-spa-home-app": "0.1.4",
    "single-spa-layout-app": "0.2.5",
    "single-spa-react-app": "0.1.4",
    "single-spa-vue": "1.7.0",
    "single-spa-vue-app": "0.1.9",
    "vue": "2.6.11",
    "vue-router": "3.1.4",
    "vue-toastr": "2.1.2",
    "zone.js": "0.10.2"
  }
}

There are several scripts in this project:

  • serve: for compile and serve the application in a development environment
  • start: for run the compiled dist folder in a production environment, in this case Heroku
  • build: for compile the application and build it as a libray in umd format
  • heroku-postbuild: for compile the application in Heroku inside its custom lifecycle
  • lint: for run eslint in all project

In dependencies config there are several libraries like bootstrap or fontawesome configured as webpack externals in dependencies like single-spa-auth-app or single-spa-vue-app.

root-application.js

/* eslint-disable no-unused-vars */
/* eslint-disable func-names */
import * as singleSpa from 'single-spa';
import 'zone.js';

import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap-vue/dist/bootstrap-vue.css';

function showWhenAnyOf(routes) {
  return function (location) {
    return routes.some((route) => location.pathname === route);
  };
}

function showWhenPrefix(routes) {
  return function (location) {
    return routes.some((route) => location.pathname.startsWith(route));
  };
}

function showExcept(routes) {
  return function (location) {
    return routes.every((route) => location.pathname !== route);
  };
}

singleSpa.registerApplication(
  'login',
  () => import('single-spa-auth-app'),
  showWhenAnyOf(['/login']),
);

singleSpa.registerApplication(
  'layout',
  () => import('single-spa-layout-app'),
  showExcept(['/login']),
);

singleSpa.registerApplication(
  'home',
  () => import('single-spa-home-app'),
  showWhenAnyOf(['/']),
);

singleSpa.registerApplication(
  'angular',
  () => import('single-spa-angular-app'),
  showWhenPrefix(['/angular']),
);

singleSpa.registerApplication(
  'vue',
  () => import('single-spa-vue-app'),
  showWhenPrefix(['/vue']),
);

singleSpa.registerApplication(
  'react',
  () => import('single-spa-react-app'),
  showWhenPrefix(['/react']),
);

singleSpa.start();

The eslint comments are indicated due to webpack external dependencies. Without the eslint comments the build process will fail.
In order to avoid duplicated css imports, bootstrap import is performed in root-application instead of every registered apps. All registered apps are declared here. Login and Home apps must be mounted when url matchs to given path, Layout app always but login path and others must be mounted when url starts with its own prefixes. Finally single-spa is started for run its lifecycle.

server.js

const express = require('express');
const path = require('path');

const port = process.env.PORT || 8080;
const app = express();

// the __dirname is the current directory from where the script is running
app.use(express.static(path.resolve(__dirname, 'dist')));

// send the user to index html page inspite of the url
app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'index.html'));
});

app.listen(port, () => {
  // eslint-disable-next-line no-console
  console.log('App listening on port:', port);
});

This express server is designed for start this application in Heroku and serve the generated dist folder and index.html.

webpack.config.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: {
    'root-application': 'root-application.js',
  },
  output: {
    publicPath: '/',
    filename: '[name].js',
  },
  module: {
    rules: [
      {
        parser: {
          system: false,
        },
      },
      {
        test: /\.js?$/,
        exclude: [path.resolve(__dirname, 'node_modules')],
        loader: ['babel-loader', 'eslint-loader'],
      },
      {
        test: /\.tsx?$/,
        loader: 'ts-loader',
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  node: {
    fs: 'empty',
  },
  resolve: {
    modules: [__dirname, 'node_modules'],
  },
  plugins: [
    new CleanWebpackPlugin({
      cleanAfterEveryBuildPatterns: ['dist'],
    }),
    new CopyWebpackPlugin([
      {
        from: path.resolve(
          __dirname,
          'node_modules/single-spa-layout-app/dist/img',
        ),
        to: path.resolve(__dirname, 'dist/img'),
      },
    ]),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'index.html'),
      inject: false,
    }),
  ],
  devtool: 'source-map',
  externals: [],
  devServer: {
    historyApiFallback: true,
    writeToDisk: true,
  },
};

It's very important to config root-application.js as entrypoint. Then are defined all rule parsers for compile all file types. And finally there are several plugins for clean dist folder and process index.html with webpack.