Create a module federation app

Developed by Jack Herrington , co-author of the "Practical Module Federation" book and technology-focused YouTuber.

create-mf-app is a tool that creates a Module Federation application, API server, or library based on one of multiple different templates.

Generating Application

This guide provides a comprehensive walkthrough on how to use the create-mf-app tool to create a Module Federation application and integrate it with Zephyr.

To execute npm package binaries, use the npx command as follows:

Terminal
npx create-mf-app

Choose a name for your application. Ensure you designate one host and at least one remote, choosing names that reflect their roles accordingly.

Terminal
? Pick the name of your app: (host)

Select the type of application:

Terminal
? Project Type: (Use arrow keys)
❯ Application
  API Server
  Library

You may use the default port option:

Terminal
? Port number: (8080)

We conducted tests using React, but other frameworks may also be compatible. See a list of supported framework here

Terminal
? Framework: (Use arrow keys)
lit-html
preact
❯ react
react-esm
solid-js
svelte
vanilla
(Move up and down to reveal more choices)

We prefer TypeScript, but Zephyr is compatible with both TypeScript and JavaScript.

Terminal
? Language:
❯ typescript
javascript

Both CSS and Tailwind are viable options for styling:

Terminal
? CSS: (Use arrow keys)
❯ CSS
Tailwind

While both packing options are viable, we strongly recommend Rspack for its performance. See benchmark of Rspack.

Terminal
? Bundler: (Use arrow keys)
Webpack
❯ Rspack

Adding Zephyr to Your Module Federation App

Installing Zephyr plugin:

Terminal
cd create-mf-app-rspack-host
npm install zephyr-webpack-plugin@latest --save

Zephyr Configuration Integration

Incorporate the Zephyr configuration into your existing setup by wrapping the current configuration object with Zephyr's functionality. To use zephyr-webpack-plugin with Rspack, replace the original content in rspack.config.js with:

rspack.config.js
1const rspack = require('@rspack/core')
2const refreshPlugin = require('@rspack/plugin-react-refresh')
3const isDev = process.env.NODE_ENV === 'development'
4const path = require('path');
5const { withZephyr } = require('zephyr-webpack-plugin')
6
7const printCompilationMessage = require('./compilation.config.js');
8
9/**
10 * @type {import('@rspack/cli').Configuration}
11 */
12module.exports = withZephyr()({
13  context: __dirname,
14  entry: {
15    main: './src/index.ts',
16  },
17
18  devServer: {
19    port: 8080,
20    historyApiFallback: true,
21    watchFiles: [path.resolve(__dirname, 'src')],
22    onListening: function (devServer) {
23      const port = devServer.server.address().port
24
25      printCompilationMessage('compiling', port)
26
27      devServer.compiler.hooks.done.tap('OutputMessagePlugin', (stats) => {
28        setImmediate(() => {
29          if (stats.hasErrors()) {
30            printCompilationMessage('failure', port)
31          } else {
32            printCompilationMessage('success', port)
33          }
34        })
35      })
36    }
37  },
38
39  resolve: {
40    extensions: ['.js', '.jsx', '.ts', '.tsx', '.json']
41  },
42  module: {
43    rules: [
44      {
45        test: /\.svg$/,
46        type: 'asset',
47      },
48      {
49        test: /\.scss$/,
50        use: [
51          {
52            loader: 'postcss-loader',
53            options: {
54              postcssOptions: {
55                plugins: {
56                  tailwindcss: {},
57                  autoprefixer: {},
58                },
59              },
60            },
61          },
62        ],
63        type: 'css',
64      },
65      {
66        test: /\.(jsx?|tsx?)$/,
67        use: [
68          {
69            loader: 'builtin:swc-loader',
70            options: {
71              sourceMap: true,
72              jsc: {
73                parser: {
74                  syntax: 'typescript',
75                  tsx: true,
76                },
77                transform: {
78                  react: {
79                    runtime: 'automatic',
80                    development: isDev,
81                    refresh: isDev,
82                  },
83                },
84              },
85              env: {
86                targets: [
87                  'chrome >= 87',
88                  'edge >= 88',
89                  'firefox >= 78',
90                  'safari >= 14',
91                ],
92              },
93            },
94          },
95        ],
96      },
97    ],
98  },
99  plugins: [
100    new rspack.container.ModuleFederationPlugin({
101      name: 'create_mf_app_host',
102      filename: 'remoteEntry.js',
103      exposes: {},
104      shared: {
105        react: { eager: true },
106        'react-dom': { eager: true },
107        'react-router-dom': { eager: true },
108      },
109    }),
110    new rspack.DefinePlugin({
111      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
112    }),
113    new rspack.ProgressPlugin({}),
114    new rspack.HtmlRspackPlugin({
115      template: './src/index.html',
116    }),
117    isDev ? new refreshPlugin() : null,
118  ].filter(Boolean),
119})

Setting a Git Origin

  1. Initialize the Git Repository:

Initialize the Git repository to start tracking your project:

Terminal
git init
  1. Stage Files for Commit:

Add all files to the staging area in preparation for the initial commit:

Terminal
git add .
  1. Create an Initial Commit:

Commit the staged files to your repository with a descriptive message:

Terminal
git commit -m "Initial commit with Zephyr"
  1. Set the Default Branch Name:

Define 'main' as the default branch for your repository:

Terminal
git branch -M main
  1. Add a Remote Origin: Zephyr requires a Git origin to establish a unique project, application, and version combination. Replace User and UserRepo with your GitHub username and repository name (You can download Github CLI here):
Terminal
gh repo create
  1. Push to GitHub (Optional):

Optionally, you can push your code to GitHub to store your changes remotely:

Terminal
git push -u origin main
Error Handling

If you encounter errors due to unset Git configurations, ensure you have set both your Git user.name and user.email, and that you have a valid 'git remote origin' set up.

[ConfigurationError: [zephyr]: git is not configured properly

    - please set git user.name and user.email

    - please set valid 'git remote origin'

]

If this error show up - create a new repository and copy the link to that repository, do:

Terminal
git remote add origin [email protected]:User/UserRepo.git

Using Zephyr

Zephyr operates as a side effect of the build process, allowing you to execute the build in watch mode for continuous updates.

Terminal
npm run build --watch
INFO

The first time you initiate a build with Zephyr, it will prompt you to log in by directing you to the Zephyr website. This login is required only on your first build; subsequent builds will not require a login.

We may require you to log in again if you removed your Zephyr configuration file ~/.zephyr locally.

Understanding Build Outputs

During the build process, Zephyr related informations are displayed as follows:

  1. Your user id.
  2. Your application URL
  3. Progress details and statistics from bundlers and us.
  4. Deployed URL.

To understand how our URLs are structured, please refer to our versioning documentation.

> npm run build

(6%)

setup before compile

ZEPHYR
Hi zackary_chapple_zephyrcloud_io!
ZEPHYR
Building to create-mf-app.createmf-app.zephyrcloudio#338

(59%)

building css|node_modules/postcss-loader/dist/cjs.js??ruleSet[1]

(62%)

sealing finish modules

ZEPHYR

uploading missing assets to zephyr (queued 2 out of 7)

ZEPHYR

Uploaded missing assets to zephyr (2 assets in 300ms, 5.74kb)

(98%)

emitting emit

ZEPHYR

Uploaded local snapshot in 193ms.

ZEPHYR

Build deployed in 195ms.

ZEPHYR

Deployed to edge:

ZEPHYR
-> https://zackary_chapple_zephyrcloud_iocreate-mf-app.createmf-app.zephyrcloudio.zephyrcloud.xyz

(100%)

done

Rspack compiled successfully in 892ms

Next Steps

You can now proceed to add remotes and start building your federated application as planned.

For insights on building micro-frontends with Rspack and Create MF App, Jack offers an informative video tutorial. We have also curated a resource page related to micro-frontend and module federation here.