Hello World with Microfrontends
OK, it’s time to get our hands dirty writing some code. We are going to start simple by building a basic multi-SPA pattern app. In this example, we will use Next.js, which is currently the most popular tool for building performant React applications. Follow these steps:
Note
For the rest of this chapter, we assume you are using pnpm
as the package manager. If not, replace pnpm
with npm
in the respective commands.
- Let’s start by creating a root folder for our app. We’ll call it
my-store
. Run the following command in your terminal:mkdir my-store
- Now, let’s
cd
intomy-store
and create our two Next.js apps, namely,home
andcatalog
, by typing the following commands in our terminal:cd my-storepnpm create-next-app@12
Or, we can type the following:
cd my-storenpx create-next-app@12
- When it prompts you to add a project name, call it
home
. It will then go through the various steps and complete the installation.The interesting thing about create-next-app is even through you define the version as @12, it will nevertheless pull the latest version of Next.js, hence to ensure consistency with the rest of this chapter we will update the version of next in package.json as follows:
"dependencies": { "next": "12", "react": "18.2.0", "react-dom": "18.2.0"
- Now delete the
node_modules
folder and the package lock file and run the pnpm i command
Important note
While you can always use yarn
or npx
to run the CLI, we recommend using pnpm
as it is 2-3 times faster than npm
or yarn
.
- Once it’s done with the setup, go ahead and create another app repeating steps 2-5. Let’s call this project
catalog
.Once complete, your folder structure would look as follows:
└── my-store/ ├── home └── catalog
- Now, let’s run the
home
app by typing the following commands:cd homepnpm run dev
- Your app should now be served on port
3000
. Verify it by visitinghttp://localhost:3000
on your browser. - Let’s get rid of the boilerplate code and add simple navigation. Locate and open up the file located at
home/pages/index.js
and replace everything within the<main></main>
tags with the following:<main className={styles.main}> <nav><a href="/">Home</a> | <a href="/catalog">Catalog</a> </nav> <h1 className={styles.title}> Home:Hello World! </h1> <h2>Welcome to my store</h2> </main>
Note that we’ve added basic navigation to navigate between the home and catalog pages. Your home app that is running on
localthost:3000
should now look as follows:
Figure 1.5 – Screenshot of the home app with two navigation links for Home and Catalog
- Now, let’s move on to the catalog app. Navigate to the index page, located at
/catalog/pages/index.js
, and again, let’s get rid of the boilerplate code and replace the contents within the<main>
tag with the following code:<main className={styles.main}> <nav><a href="/">Home</a> | <a href="/catalog">Catalog</a> </nav> <h1 className={styles.title}> Catalog:Hello World! </h1> <h2>List of Products</h2> </main>
Now, since we already have the home page being served on port
3000
, we will run our catalog app on port3001
. - We do this by adding the port flag for the
dev
command within thescripts
section of thecatalog/package.json
file, as follows:"scripts": { "dev": "next dev -p 3001 … }
- Now, running
pnpm run dev
from within the catalog app should run the catalog app onhttp://localhost:3001
. You can see this in the following screenshot:
Figure 1.6 – Screenshot of the catalog app running on port 3001
The next step is to wire these up such that when the user hits localhost:3000
, it directs them to the home app, and when the user hits localhost:3000/catalog
, they are redirected to the catalog app. This is to ensure that both apps feel as if they are part of the same app, even though they are running on different ports.
- We do this by setting the
rewrites
rule in thehome/next.config.js
file, as follows:const nextConfig = { reactStrictMode: true, swcMinify: true, async rewrites() { return [ { source: '/:path*', destination: `/:path*`, }, { source: '/catalog', destination: `http://localhost:3001/catalog`, }, { source: '/catalog/:path*', destination: `http://localhost:3001/catalog/:path*`, }, ] }, } module.exports = nextConfig
As you can see from the preceding code, we simply tell Next.js that if the source URL is
/catalog
, then load the app fromlocalhost:3001/catalog
. - Before we test it out, there is another small change needed to the catalog app. As you can see, the catalog app will be served on the root of port
3001
, but what we would like is for it to be served at:3000/catalog
. This is because with the rewrite we did earlier, Next.js will expect the catalog apps and its assets to be available at/catalog/*
. We can do this by setting thebasePath
variable in thecatalog/next.config.js
file as follows:const nextConfig = { reactStrictMode: true, swcMinify: true, basePath:'/catalog' }
- Now, to test that this is working fine, we will run up both of the apps in two different terminal windows by navigating to the home and catalog apps and running the
pnpm run
dev
command. - Open up
http://localhost:3000
in your browser and verify that the home app is loaded. Click on the Catalog link and verify that the catalog page does load up athttp://localhost:3000/catalog
. Notice that the app catalog that’s running individually on port3001
is sort of “proxied” to load up within a unique URL of the parent/host app. This is one of the key principles of microfrontends, where apps running on different ports and different locations are “stitched” together to make it look like they are a part of the same application.
With that, we come to the end of creating our very first microfrontend with the multi-SPA pattern. We will look at the micro apps pattern in more detail in the upcoming chapters. This pattern meets the majority of the use cases for building microfrontends and checks all the key principles of microfrontends, which we are going to see in the next chapter.