Example of using webPack5 Module Federation “Micro front-end” VUE demo

Recently there was a need to consider using a “micro front end”. Understood some, this article makes a sorting record

Module Federation is a new webpack5 “micro front end” concept. This article introduces the actual operation of the vue version

  • The official document: webpack.docschina.org/concepts/mo…

Relationship in Demo:

Relationship: App1 exposes “microservices” and App2 uses “microservices” of App1.

In the code

The directory structure

. ├ ─ ─ the README. Md ├ ─ ─ app1 / / app1 exposed "micro" service │ ├ ─ ─ package. The json │ ├ ─ ─ public │ │ └ ─ ─ index. The HTML │ ├ ─ ─ the SRC │ │ ├ ─ ─ App. Vue │ │ ├ ─ ─ components │ │ │ └ ─ ─ the Header. The vue │ │ └ ─ ─ the main, js │ └ ─ ─ webpack. Config. Js └ ─ ─ app2 / use/app2 app1 "micro" service ├ ─ ─ └── public │ ├─ index.html │ ├─ SRC │ ├── app.vue │ ├─ key.js │ ├─ webpack.htmCopy the code

App1 and App2 are part of the same code (environment)

  • The same package. The json
  • SRC/main. Same js
  • Public/index. HTML is the same
// package.json
{
  "scripts": {
    "start": "webpack serve"."build": "webpack"
  },
  "devDependencies": {
    "vue-loader": "^ 15.9.3"."vue-template-compiler": "^ 2.6.12." "."@babel/core": "^ 7.14.3"."babel-loader": "^ 8.2.2"."html-webpack-plugin": "^ 5.3.1"."webpack": "^ 5.38.1"."webpack-cli": "^ 4.7.2." "."webpack-dev-server": "^ 3.11.2"
  },
  "dependencies": {
    "vue": "^ 2.6.12." "}}// src/main.js
import Vue from "vue";
import App from "./App.vue";

new Vue({
    el: '#app'.render: h= > h(App)
})

// public/index.html
<html>
<head></head>
<body>
<div id="app"></div>
</body>
</html>
Copy the code

Component code for App1

  • App.vue
  • components/Header.vue
// App.vue
<template>
  <div id="app" style="border: 1px solid cornflowerblue">
    <h2>I am a app. Vue</h2>
    <Header name="app1"/>
  </div>
</template>
<script>
import Header from './components/Header.vue'
export default {
  components: {
    Header
  }
}
</script>

// components/Header.vue
<template>
    <div style="border: 1px solid olivedrab">
        <h4>I'm header.vue, and this is the passthrough: {{name}}</h4>
    </div>
</template>
<script>
export default {
    props: {
        name: {
            type: String.default: ' '}}}</script>
Copy the code

App2 component code

  • The “microservice” of App1 is used in app. vue
// App.vue
<template>
  <div id="app">
    <Header name="app222222"/>// Here app2 uses app1's "microservice"<br>
    <qwe></qwe>// Here app2 uses app1's "microservice"</div>
</template>
<script>

export default {
  components: {
    Header: () = > import('app1/Header'), // Here app2 uses app1's "microservice"
    qwe: () = > import('app1/appIndex') // Here app2 uses app1's "microservice"}}</script>
Copy the code

Implementation key: webpack.config.js

App1 webpack.config.js (exposing “microservices” to the outside world)

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require("webpack").container;

module.exports = {
    target: 'web'.entry: './src/main.js'.mode: "development".devServer: {
      port: 3000.hot: true.open: true.contentBase: path.join(__dirname, "dist"),},module: {
        rules: [{test: /.js$/,
                loader: 'babel-loader'.exclude: /node_modules/
            },
          {
            test: /.vue$/,
            loader: 'vue-loader'}},plugins: [
        // Make sure to include this plugin!
        new VueLoaderPlugin(),
        new HTMLWebpackPlugin({
            template: path.resolve(__dirname, './public/index.html')}),new ModuleFederationPlugin({
            // Files provided for loading by other services
            filename: "remoteEntry.js".// Unique ID, used to mark the current service
            name: "app1".library: { type: "var".name: "app1" },
            ${name}/${expose}
            exposes: {
              './Header': "./src/components/Header.vue".// App1 exposes the "microservice" Header (component)
              './appIndex': "./src/App.vue".// app1 exposes "microservice" appIndex (component)}}})]Copy the code

App2’s webpack.config.js (accepts app1’s “microservices” (components))

const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HTMLWebpackPlugin = require('html-webpack-plugin');
const { ModuleFederationPlugin } = require("webpack").container;

module.exports = {
    target: 'web'.entry: './src/main.js'.mode: "development".devServer: {
      port: 3001.hot: true.open: true.contentBase: path.join(__dirname, "dist"),},module: {
        rules: [{test: /.js$/,
                loader: 'babel-loader'.exclude: /node_modules/
            },
          {
            test: /.vue$/,
            loader: 'vue-loader'}},plugins: [
        // Make sure to include this plugin!
        new VueLoaderPlugin(),
        new HTMLWebpackPlugin({
            template: path.resolve(__dirname, './public/index.html')}),new ModuleFederationPlugin({
          name: "app2".remotes: {
            app1: "app1@http://localhost:3000/remoteEntry.js".// (accept app1's "microservice"), remoteEntry can be thought of as the intermediary agent)}}})]Copy the code

Results show

App1: NPM run start

Then app2 can NPM run start

You can see that within App2, you can use the exposed “microservices” (components) of App1


Code words are not easy