Micro Frontend Solution 6 - Build & Deploy

Micro Frontend Build

There are some things to note when bundling micro frontend projects. Take webpack as an example:

AMD Modules

In previous articles, we mentioned that our loader is based on System.js. So the final bundle of our micro frontend modules must conform to module specifications. We use the AMD module specification to build our modules.

Specify Base Path

Since the module loader calls the module entry file after bundling, To clearly manage each module and correctly load all our module resources, we specify a publicPath for all module resources.

Below is a simple webpack configuration. I only list the necessary options. It’s not a complete webpack config. I’ll provide a complete micro frontend demo later for reference. These configurations are modified based on create-react-app. Once you understand the intent of the config and what kind of bundle we end up with, no matter how the build tool changes or the tech stack changes, it can always be integrated into the micro frontend.

Here is the project.json content for reference when reading the configuration file:

// project.json
{
    "name": "name", // module name
    "path": "/project", // module url prefix
    "prefix": "/module-prefix/", // module file path prefix
    "main": "/module-prefix/main.js", // module render entry file
    "store": "/module-prefix/store.js", // module external interface
    "base": true // whether it's the base app
  }

// Import project config file, one of the necessary files for the module loader
const projectConfig = require('./project.json')

let config = {
  entry: {
    main: paths.appIndexJs, // entry file, one of the necessary files for the module loader
    store: paths.store // external api reducer file, one of the necessary files for the module loader
  },
  output: {
    path: paths.appBuild,
    filename: '[name].js?n=[chunkhash:8]',
    chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
    publicPath: projectConfig.prefix, // specify the configured publicPath in output
    libraryTarget: 'amd', // output AMD module for system.js loading
    library: projectConfig.name, // module name
  },
  },
  module: {
    rules: [
      {
        oneOf: [
          {
            test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
            // loader: 'happypack/loader?id=url',
            loaders: [{
              loader: require.resolve('url-loader'),
              options: {
                limit: 5000,
                name: 'static/media/[name].[hash:8].[ext]',
                publicPath: projectConfig.prefix, // add publicPath to static file loaders
              },
            }]
          },
          {
            test: /\.(js|jsx|mjs)$/,
            include: paths.appSrc,
            loader: 'happypack/loader?id=babel',
            options: {
                name: 'static/js/[name].[hash:8].[ext]',
                publicPath: projectConfig.prefix, // add publicPath to static file loaders
              },
          },
          {
            loader: require.resolve('file-loader'),
            exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
            options: {
              name: 'static/media/[name].[hash:8].[ext]',
              publicPath: projectConfig.prefix, // add publicPath to static file loaders
            },
          },
        ],
      },
    ],
  },
}

Deployment

No matter how front-end SPA deployment is automated or how tools change, it’s always about placing the bundled static files in the correct location on the server. Micro frontend deployment is a process of application aggregation. How do we finally integrate each module into a complete project?

Micro Frontend Application Directory

It’s usually placed in a static directory configured by nginx, or another web container’s static directory. Looking at this directory structure, you should understand why we need to configure publicPath.

├── index.html              // The browser loads this index.html first, which imports a bootstrap.js file
├── bootstrap.js            // This bootstrap.js is the module loader bundled code.
│                           // The module loader first loads `project.config.js` to get all module configs.
│                           // Then it loads each module's main.js, registers the app, and injects store.js
│
├── project.config.js       // This file stores all module configs for the project, auto-generated
│                           // Mentioned earlier as project config automation — the only dynamic file in the project.
│                           // When modules are updated or new modules are added, they're automatically mounted.
│                           // It iterates through each module's project.json, extracts content, and merges them
│
├── projectA                // Module A directory
│   ├── asset-manifest.json
│   ├── favicon.ico
│   ├── main.js             // Render entry file
│   ├── manifest.json
│   ├── project.json        // Module config file
│   ├── static
│   │   ├── js
│   │   │   ├── 0.86ae3ec3.chunk.js
│   │   └── media
│   │       └── logo.db0697c1.png
│   └── store.js            // Exported store.js file
└── projectB                // Module B (important file locations are same as Module A)
    ├── asset-manifest.json
    ├── main.js
    ├── manifest.json
    ├── project.json
    ├── static
    │   ├── js
    │   │   ├── 0.86ae3ec3.chunk.js
    │   └── media
    │       └── logo.db0697c1.png
    └── store.js

Config Automation

Each of our modules has the config file described above. When our project has multiple modules, we need to aggregate all module config files. I also wrote a script for this:

micro-auto-config

Usage:

npm install micro-auto-config -g

# Start the script with pm2 in the project root directory to enable config automation
pm2 start micro-auto-config --name your-project-name-auto-config

After this, project.config.js will be auto-generated, and will be regenerated when modules change.

To be continued …

Related Articles

Micro Frontend Solution 1 - Thinking

Micro Frontend Solution 2 - Single-SPA

Micro Frontend Solution 3 - Module Loader

Micro Frontend Solution 4 - Message Bus

Micro Frontend Solution 5 - Route Distribution

Micro Frontend Solution 6 - Build & Deploy

Micro Frontend Solution 7 - Static Data

Micro Frontend Solution 8 - Secondary Build

Demo

Micro Frontend Demo

Micro Frontend Module Loader

Micro Frontend Base App Source

Micro Frontend Submodule Source

Article Link:

/en/archive/micro-frontend-solution-6-build-deploy/

# Related Articles