Using Module Federation in vue/cli

Posted by phyzar on Sun, 21 Nov 2021 05:04:14 +0100

Using Module Federation in vue/cli

The new features of webpack 5 are developed in modules. Multiple independent builds can form an application. There should be no dependency between these independent builds, so they can be developed and deployed separately. This is often referred to as a micro front end, but it is not limited to this.

We divide it into local module and remote module.

The local module is a common module, which is a part of the current construction; The remote module does not belong to the current build and is loaded from the so-called container at run time.

Loading a remote module is considered an asynchronous operation. When using a remote module, these asynchronous operations will be placed in the load operation of the next chunk between the remote module and the portal. If there is no chunk load operation, the remote module cannot be used.

The load operation of chunk is usually implemented by calling import(), but old syntax such as require.ensure or require([...]) is also supported.

A container is created by a container entry that exposes asynchronous access to a specific module. The exposed access is divided into two steps:

Step 1: load module (asynchronous)

Step 2: execution module (synchronous)

Step 1 will be completed during chunk loading. Step 2 will be completed during interleaving with other modules (local and remote). In this way, the execution order is not affected by the conversion of modules from local to remote or from remote to local.

Containers can be nested, and containers can use modules from other containers. Cyclic dependencies can also be used between containers.

Using Module Federation in vue/cli requires only the following steps:

home project

// vue.config.js
module.exports = {
  publicPath: 'http://localhost:8084/',

  chainWebpack: (config) => {
    config
      .plugin('module-federation-plugin')
      .use(require('webpack').container.ModuleFederationPlugin, [{
        name: "home", // Module name
        filename: "remoteEntry.js",
        exposes: { // Externally exposed components
          './HelloWorld': './src/components/HelloWorld.vue'
        },
    }])
  },

  devServer: {
    port: 8084,
    hot: true,
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
      "Access-Control-Allow-Headers":
        "X-Requested-With, content-type, Authorization",
    }
  }
}

app project

// vue.config.js
module.exports = {
  publicPath: 'http://localhost:8085/',

  chainWebpack: (config) => {
    config
      .plugin('module-federation-plugin')
      .use(require('webpack').container.ModuleFederationPlugin, [{
        name: "app",
        remotes: { // Import
          home: 'home@http://localhost:8084/remoteEntry.js',
        },
    }])
  },

  devServer: {
    port: 8085,
    hot: true,
    headers: {
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS",
      "Access-Control-Allow-Headers":
        "X-Requested-With, content-type, Authorization",
    }
  }
}

Use components

// Use the components in the home project
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png">
    <HelloWorld msg="1111"/>
  </div>
</template>

<script>
export default {
  name: 'App',
  components: {
    HelloWorld: () => import('home/HelloWorld')
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

Topics: Javascript node.js Vue.js