The core goal of the micro front end is to break up the boulder application into several loosely coupled micro-applications that can be autonomous. Many of the designs of Qiankun are based on this principle, such as HTML Entry, sandbox and inter-application communication. Only in this way can we ensure that microapplications can be developed independently and run independently.

One: the core value of the micro front-end architecture

  • Stack independent
  • Independent development and deployment
  • The incremental upgrade
  • Independent run time

Two: get started quickly

We divide it into master apps and micro apps. The previous idea was to generate the basic configuration of both projects directly through vue-CLI scaffolding. But halfway through, vue-CLI is too hard to use the webpack5 module federation (there have been various errors, I think the vue-CLI4.x webpack version is 4.x, which is incompatible with Webpack 5 in some places). Build your own configuration using webpack5.

Webpack configuration

Start with WebPack5 to set up a basic configuration to get the project running.

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {VueLoaderPlugin} = require('vue-loader/dist/index');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');

module.exports = {
  mode: 'development'.entry: path.resolve(__dirname, './src/main.js'),
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'js/[name].js'
  },
  module: {
    rules: [{test: /.vue$/,
        use: [
          'vue-loader'] {},test: /.css$/,
        use: [
          'style-loader'.'css-loader'] {},test: /.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'}},devServer: {
    // Change webpack4 contentBase to the following
    static: {
      directory: path.join(__dirname, './dist')},port: 8080
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './index.html'),
      filename: 'index.html'.title: 'qiankun-root-app'
    }),
    new VueLoaderPlugin(),
    new CleanWebpackPlugin()
  ]
};
Copy the code

Qiankun configuration

Main application:

  1. The installationqiankun

Yarn Add Qiankun # or NPM I Qiankun-s

  1. Register the microapplication in the main application and start it
// main.js
import {registerMicroApps, start} from 'qiankun';

registerMicroApps([
  {
    // The name of the microapplication
    name: 'vue-app'.// Microapplication entry
    entry: 'http://localhost:8081/'.// The container node selector for the microapplication
    container: '#vue-app'.// Activation rules for microapplications
    activeRule: '/vue'}]); start();Copy the code

There should be a route and node matching the activation rule in the main application;

<template>
    <div>
        <router-link to="/">Home page</router-link>
        <router-link to="/vue">Vue applications</router-link>
    </div>
    <router-view></router-view>
    <div id="vue-app"></div>
</template>
Copy the code

Son:

  1. Export the corresponding lifecycle hooks (bootstrap,mount,unmount)
// main.js
export async function bootstrap() {
  console.log('[vue] vue app bootstraped');
}

export async function mount(props) {
  render(props);
}

export async function unmount() {
  instance.unmount();
  instance._container.innerHTML = ' ';
  instance = null;
  router = null;
  history.destroy();
}
Copy the code
  1. Configure the packaging tool for microapplications
// webpack.config.js
const packageName = require('./package.json').name;

module.exports = {
  output: {
    library: `${packageName}`.libraryTarget: 'umd'.// WebPack5 jsonpFunction changed to chunkLoadingGlobal
    chunkLoadingGlobal: `webpackJsonp_${packageName}`,}};Copy the code

Three: Common problems

1. The routing

  • (1) : Both main and micro applications are bestThe history (createWebHistory)Mode;

Main application:

// router/index.js
import {createRouter, createWebHistory} from 'vue-router';

const Home = () = > import('.. /src/components/Home.vue');
const routes = [
  {path: '/'.component: Home}
];


const router = createRouter({
  history: createWebHistory('/'),
  routes
});

export default router;
Copy the code

Application:

Export routes. Instantiate routes in the entry file.

// main.js
import {createRouter, createWebHistory} from 'vue-router';
import routes from '.. /router/index'

let instance = null;
let router = null;
let history = null;

function render(props = {}) {
  const {container} = props;
  // Base must be set for histroy routes
  history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/vue' : '/');
  router = createRouter({
    history,
    routes
  });
  
  instance = createApp(App);
  instance.use(router);
  instance.mount(container ? container.querySelector('#app1') : '#app1');
}
Copy the code
  • (2) : cross-domain problems

Subapplications need to be configured to allow cross-domain:

// webpack.config.js
devServer: {
  headers: {
    'Access-Control-Allow-Origin': The '*',}},Copy the code

2. Reuse common dependency libraries

usewebpackexternalsThe implementation.

Main application:

// webpack.config.js
externals: {
  'vue': 'Vue'.'element-plus': 'ElementPlus'
}
Copy the code
// index.html
<link rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css">
<script src="//unpkg.com/vue@next"></script>
<script src="//unpkg.com/element-plus"></script>
Copy the code

Micro application: index. HTML address to add ignore, but add ignore error;

No solution has been found; There seems to be a problem with Vue-Router4;

// webpack.config.js
externals: {
  'vue': 'Vue'.'element-plus': 'ElementPlus'
}
Copy the code
// index.html
<link ignore rel="stylesheet" href="//unpkg.com/element-plus/dist/index.css">
<script ignore src="//unpkg.com/vue@next"></script>
<script ignore src="//unpkg.com/element-plus"></script>
Copy the code
// main.js
import ElementPlus from 'element-plus';
instance.use(ElementPlus);
Copy the code

3. Reuse common components and methods

  • (1) : Directly used when registering microapplicationspropsAttribute passing;

Main application:

// main.js
import HeaderComponent from '.. /src/common/header.vue'
import FooterComponent from '.. /src/common/footer.vue'
window.commonComponents = {
  HeaderComponent,
  FooterComponent
};
let commonComponents = window.commonComponents || {};
registerMicroApps([
  {
    ...
    props: {
      data: {
        commonComponents
      }
    }
  }
]);

// Shared components must have multiple instances enabled
start({ singular: false })
Copy the code

Application:

// main.js
export async function mount(props) {
  window.commonComponents = props.data.commonComponents;
  render(props);
}
Copy the code
// Home.vue
components: {
  HeaderComponent: window.__POWERED_BY_QIANKUN__ ? window.commonComponents.HeaderComponent : ' '.FooterComponent: window.__POWERED_BY_QIANKUN__ ? window.commonComponents.FooterComponent : ' '
}
Copy the code
  • (2) : Usewebpack5Module federal

Main application: put common components and methods into a separate JS and export them;

// commonExport.js
import HeaderComponent from './src/common/header.vue'
import FooterComponent from './src/common/footer.vue'

import utils from './src/utils/index.js'

export {
  HeaderComponent,
  FooterComponent,
  utils
}
Copy the code
// webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;

new ModuleFederationPlugin({
  name: 'root_app'.filename: "root_app.js".exposes: {
    './commonExport': './commonExport'}})Copy the code

Application:

// webpack.config.js
plugins: [
  new ModuleFederationPlugin({
    name: 'vue_app'.filename: "vue_app.js".remotes: {
      rootApp: 'root_app@http://localhost:8080/root_app.js'}})]Copy the code
// Home.vue
import {onMounted} from 'vue';
// Use common components and methods
import {HeaderComponent, utils} from 'rootApp/commonExport'

export default {
  name: 'Home'.components: {
    HeaderComponent
  },
  setup() {
    onMounted(() = >{ utils.commonFn(); }}})Copy the code

4. Microapp loaded resources will be 404

Create a public-path.js microapplication and import it in main.js.

if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
Copy the code
import './public-path';
Copy the code

5. How do microapplications operate independently?

// main.js
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}
Copy the code

6. 404 is refreshed in the micro-application path

This is usually because you are using browser mode routing, which requires the cooperation of the server. The development environment needs to modify devServer

// webpack.config.js
devServer: {
  // Resolve microapplication refresh error 404
  proxy: {
    '/vue/': {
      target: 'http://localhost:8080'.changeOrigin: true.pathRewrite: {
        '^/vue': ' '}}},historyApiFallback: true
},
Copy the code