Skip to content
Branch: master
Find file Copy path
Find file Copy path
3 contributors

Users who have contributed to this file

@frehner @TheMcMurder @joeldenning
105 lines (70 sloc) 11.6 KB
id title sidebar_label
Frequently Asked Questions

What does single-spa do?

single-spa is a top level router. When a route is active, it downloads and executes the code for that route.

The code for a route is called an "application", and each can (optionally) be in its own git repository, have its own CI process, and be separately deployed. The applications can all be written in the same framework, or they can be implemented in different frameworks.

Is there a recommended setup?

We recommend a setup that uses in-browser ES modules + import maps (or SystemJS to polyfill these if you need better browser support). This setup has several advantages:

  1. Common libraries are easy to manage, and are only downloaded once. You can also preload these for a small speed boost as well using the standard preload spec.
  2. Sharing code / functions / variables is as easy as import/export, just like in a monolithic setup
  3. Lazy loading applications is easy, which enables you to speed up initial load times
  4. Each application (AKA microservice, AKA ES module) can be independently developed and deployed. Teams are enabled to work at their own speed, experiment (within reason as defined by the organization), QA, and deploy on thier own schedules. This usually also means that release cycles can be decreased to days instead of weeks or months
  5. A great developer experience (DX): go to your dev environment and add an import map that points the application's url to your localhost. See "What is the DX like?" for more details.

What is the impact to performance?

When setup in the recommended way, your code performance and bundle size will be nearly identical to a single application that has been code-split. The major differences will be the addition of the single-spa library (and SystemJS if you chose to use it). Other differences mainly come down to the difference between one (webpack / rollup / etc.) code bundle and in-browser ES modules.

Can I have only one version of (React, Vue, Angular, etc.) loaded?

Using the recommended setup, you setup your import map to download that once. Then, tell each application to not bundle that application code; instead, it will given to you at runtime in the browser. See webpack’s externals (other bundlers have similar options) for how to do this.

You do have the option of not excluding those libraries (for example if you want to experiment with a newer version or a different library) but be aware of the effect that will have on user's bundle sizes and application speed.

What are import maps?

Import maps improve the developer experience of in-browser ES modules by allowing you to write something like import React from "react" instead of needing to use an absolute or relative URL for your import statement. The same is also true of importing from other single-spa applications, e.g. import {MyButton} from "styleguide". The import-map spec is currently in the process of being accepted as a web standard and at the time of writing has been implemented in Chrome, and a polyfill for browsers >= IE11 has been implemented by SystemJS >= 3.0. Also see the recommended setup

How can I share application state between applications?

In general, we recommend trying to avoid this — it couples those apps together. If you find yourself doing this frequently between apps, you may want to consider that those separate apps should actually just be one app.

Generally, it’s better to just make an API request for the data that each app needs, even if parts of it have been requested by other apps. In practice, if you’ve designed your application boundaries correctly, there will end up being very little application state that is truly shared — your friends list has different data requirements than your social feed.

However, that doesn’t mean it can’t be done. Here are several ways:

  1. Create a shared API request library that can cache requests and their responses. If somone hits an API, and then that API is hit again by another application, it just uses the cache
  2. Expose the shared state as an export, and other libraries can import it. Observables (like RxJS) are useful here since they can stream new values to subscribers
  3. Use custom browser events to communicate
  4. Use cookies, local/session storage, or other similar methods for storing and reading that state. These methods work best with things that don't change often, e.g. logged-in user info.

Please note that this is just talking about sharing application state: sharing functions, components, etc. is as easy as an export in one project and an import in the other.

Should I use frontend microservices?

If you’ve ran into some of the headaches a monolithic repo has, then you should really consider it.

In addition, if your organization is setup in a Spotify-type model (e.g. where there are autonomous squads that own full-stack features) then microservices on the frontend will fit very well into your setup.

However, if you’re just starting off and have a small project or a small team, we would recommend you stick with a monolith (i.e. not microservices) until you get to the point that scaling (e.g. organizational scaling, feature scaling, etc.) is getting hard. Don’t worry, we’ll be here to help you migrate when you get there.

Can I use more than one framework?

Yes. However, it’s something you’ll want to consider hard because it splits your front-end organization into specialities that aren’t compatible (e.g. a React specialist may have problems working in an Angular app), and also causes more code to be shipped to your users.

However, it is great for migrations away from an older or unwanted library, which allows you to slowly rip out the code in the old application and replace it with new code in the new library (see Google results for the strangler pattern).

It also is a way to allow large organizations to experiment on different libraries without a strong commitment to them.

Just be conscious of the effect it has on your users and their experience using your app.

What is the developer experience (DX) like?

If you're using the recommended setup for single-spa, you'll simply be able to go to your development website, add an import map that points to your locally-running code, and refresh the page.

There's a library that you can use, or you can even just do it yourself - you'll note that the source code is pretty simple. The main takeaway is that you can have multiple import maps and the latest one wins - you add an import map that overrides the default URL for an application to point to your localhost.

We're also looking at providing this functionality as part of the Chrome/Firefox browser extension.

Finally, this setup also enables you to do overrides in your production environment. It obviously should be used with caution, but it does enable a powerful way of debugging problems and validating solutions.

As a point of reference, nearly all developers we've worked with prefer the developer experience of microservices + single-spa over a monolithic setup.

Can each single-spa application have its own git repo?

Yes! You can even give them their own package.json, webpack config, and CI/CD process, using SystemJS to bring them all together in the browser.

Can single-spa applications be deployed independently?

Yes! See next section about CI/CD.

What does the CI/CD process look like?

In other words, how do I build and deploy a single-spa application?

With the recommended setup, the process generally flows like this:

  1. Bundle your code and upload it to a CDN.
  2. Update your dev environment's import map to point to the that new URL. In other words, your import map used to say "styleguide": "" and now it should say "styleguide": ""

Some options on how to update your import map include:

  • Server render your index.html with the import map inlined. This does not mean that your DOM elements need to all be server rendered, but just the <script type="systemjs-importmap> element. Provide an API that either updates a database table or a file local to the server.
  • Have your import map itself on a CDN, and use import-map-deployer or similar to update the import map during your CI process. This method has a small impact on performance, but is generally easier to setup if you don't have a server-rendered setup already. (You can also preload the import map file to help provide a small speed boost). See example travis.yml. Other CI tools work, too.

Create React App

Currently Create React App (CRA) requires ejecting or using a tool to modify the webpack config. You can also consider some of the popular alternatives to CRA.

When you use the recommended setup the following things need to change (as of CRA v3.0.1):

  1. Remove Webpack optimizations block, because they add multiple webpack chunks that don't load each other
  2. Remove html-webpack plugin
  3. Change output.libraryTarget to System, UMD, or AMD.

CRA does not allow you to change those items without ejecting or using another tool.

Code splits

Single spa supports code splits. There are so many ways to code split we won't be able to cover them all, but if you're using the recommended setup with webpack you'll need to do at least two things:

  1. Set the __webpack_public_path__ dynamically so webpack knows where to fetch your code splits (webpack assumes they are located at the root of the server and that isn't always true in a single-spa application). An example implementation would work as long as the variable is set prior to loading a code split, and you can also track this SystemJS issue for progress on making this easier.
  2. Set either output.jsonpFunction or output.library to ensure that each app's webpack doesn't collide with other apps' webpack. jsonpFunction is preferred.
You can’t perform that action at this time.