Micro front end development

Keywords: Front-end

1, Overview of micro front end

one    What is a micro front end?

In order to solve the limitations of change and expansion caused by a large piece of back-end services, micro service architecture has emerged.

However, the more and more important front-end engineering is also facing the same problem. It is natural to think of applying (copying) the idea of micro services to the front-end, so there is the concept of "micro frontends". That is, an architecture style composed of multiple front-end applications delivered independently. Specifically, the front-end application is decomposed into smaller and simpler pieces that can be developed, tested and deployed independently, but it is still a cohesive single product in the eyes of users.

Our common background projects are usually as follows:

 

If our project needs to develop a new function and another project has developed this function, we want to reuse it directly.

Note: what we need is the content of the function page of other people's projects, and we don't need the top navigation and menu of other people's projects.

A stupid way is to directly copy the code of other people's project page, but in case other people are not developed by vue, or the vue version and UI library are different, as well as the operations (route interception, authentication, etc.) before other people's page is loaded, we need to copy it. The more important problem is how to update other people's code synchronously. Even when other projects adopt other technology stacks, how to integrate? Obviously copying code won't work.

By analogy with the concept of front-end components, we can regard each separated sub application as an application level component, and each application level component is dedicated to a specific business function (such as commodity management, order management, etc.). This actually talks about the principle of micro front-end splitting: taking business functions as the basic unit. After splitting, the structure of the whole system has also changed:

 

As shown in the figure above, the front-end architecture of traditional large-scale single page applications is on the left. All modules are in one application, and the application itself is responsible for routing management, which is the way of application routing distribution; On the right is the system architecture in the base mode. Each sub application is not related to each other and runs on different services separately. The base application selects which application to load into the page according to the routing, which is the way to route and distribute applications. This method greatly reduces the coupling of each module, and the main problem to be solved in the micro front end is how to split and organize these sub applications.

Typical Vue router based Vue applications are very similar to this architecture:

 

two    Problems of Big Mac project

  • More and more code, slower and slower packaging, troublesome deployment and upgrading, and more consideration needs to be given to the upgrading of some plug-ins and the modification of public components, which can easily affect the whole body.
  • The project is too large, with more participants, code specifications are difficult to manage, and code conflicts are frequent.
  • Products have complete functions, but customers often only need some of them. After stripping unnecessary codes, you need to make versions independently and maintain them independently to increase labor costs.

The birth of micro front-end is also to solve the above problems:

  • Reuse (embed) other people's project pages, but other people's projects run on their own environment.
  • Big Mac applications are divided into small projects. These small projects are developed and deployed independently and can be freely combined for sale.

Benefits of using micro front end:

  •       Independent of the technology stack, each sub project can freely choose the framework and formulate its own development specifications.
  •      Rapid packaging, independent deployment, no mutual influence and simple upgrade.
  •      It can easily reuse the existing functional modules to avoid repeated development.

2, Common micro front end solutions

At present, the mainstream micro front-end solutions include the following:

  •  iframe
  • The base mode is mainly based on routing distribution. qiankun and single spa are based on this mode
  • Combinatorial integration, that is, build components separately and load them on demand, similar to the form of npm package
  • EMP, mainly based on Webpack5 Module Federation
  • Web Components

Iframe: it is a traditional micro front-end solution. It is implemented based on iframe tag, with low technical difficulty, good isolation and compatibility, but poor performance and use experience. It is mostly used to integrate third-party systems;

Base mode: mainly based on route distribution, that is, a base application monitors routes and loads different applications according to routing rules to realize decoupling between applications;

Combinatorial integration: package and publish components separately, and then combine them at build or run time.

EMP: Based on Webpack5 Module Federation, a decentralized micro front-end implementation scheme, which can not only isolate applications, but also easily realize resource sharing and communication between applications.

Web Components: it is an official component-based scheme. It realizes the micro front end by encapsulating components to a higher degree. However, at present, the compatibility is not good enough and has not been popularized.

Generally speaking, iframe is mainly used for third-party systems that are simple and have low performance requirements; At present, combined integration is mainly used for front-end component, not micro front-end; Pedestal mode, EMP and Web Components are the mainstream micro front-end solutions.

At present, there are two most commonly used solutions for micro front-end: iframe scheme and pedestal mode scheme.

one    iframe scheme

iframe is familiar to everyone. It is easy to use and provides natural js/css isolation. It also brings inconvenience to data transmission. Some data cannot be shared (mainly local storage, global variables and public plug-ins). When the two projects have different sources (cross domain), data transmission needs to rely on postMessage.

iframe has many holes, but most of them have solutions:

1. Page loading problem

iframe shares the connection pool with the main page, and the browser has restrictions on the connection of the same domain, so it will affect the parallel loading of the page and block the onload event. Each click needs to be reloaded. Although display:none can be used for caching, too much page caching will cause the computer to jam. (cannot be resolved)

2. Layout issues

iframe must be given a specified height, otherwise it will collapse.

Solution: the sub project calculates the height in real time and sends it to the main page through postMessage. The main page dynamically sets the iframe height. In some cases, there will be multiple scroll bars, resulting in poor user experience.

3. Pop up window and mask layer

The pop-up window can only be vertically and horizontally centered within the iframe range, but cannot be vertically and horizontally centered on the whole page.

Solution 1: it is solved synchronously with the frame page message, and the pop-up message is sent to the main page. The main page pops up, which greatly changes the original project and affects the use of the original project.

Solution 2: change the style of pop-up window: hide the mask layer and change the position of pop-up window.

  4.   div in iframe cannot be full screen

The full screen of pop-up window refers to the full screen in the visual area of the browser. This full screen refers to the full user screen.

In the full screen scheme, the native method uses Element.requestFullscreen(), plug-in: Vue fullscreen. When the page is in iframe, the full screen will report an error, and the dom structure is disordered.

Solution: set the allow="fullscreen" attribute on the iframe tag

  5.   Browser forward / backward problem

Iframe and the main page share a browsing history, and iframe will affect the forward and backward of the page. Most of the time, iframe redirection will cause the forward and backward function of the browser to fail to work normally. And iframe page refresh will reset (for example, jump from the list page to the details page, and then refresh, and return to the list page), because the address bar of the browser has not changed, and the src of iframe has not changed.

  6.   iframe loading failure is difficult to handle

Non homologous iframe s do not support onerror events in Firefox and chorme.

Solution 1: determine whether the title of the page is 404 or 500 in the onload event

Solution 2: use try catch to solve this problem. An exception will be thrown when trying to get the contentDocument.

two    Base mode scheme

The pedestal mode scheme is represented by single spa and qiankun. Here I choose qiankun.

qiankun is an open source framework of ant financial services, which is based on single spa. On the basis of single spa, it realizes out of the box. Except for some necessary modifications, the subproject can be easily accessed with few changes.

qiankun framework official website: https://qiankun.umijs.org/zh/.

There are two common methods for the entry file of micro front-end sub projects: JS entry and HTML entry. Pure single spa uses JS entry, while qiankun supports both JS entry and HTML entry.

JS entry has strict requirements:

(1) package css into js

(2) remove chunk-vendors.js,

(3) remove the hash value of the file name

(4) place the single spa mode entry file (app. JS) in the index.html directory. Other files remain unchanged because the path of app.js should be intercepted as the publicPath.

It is recommended to use HTML entry, which is as simple as iframe, but the user experience is much better than iframe. After qiankun requests the index.html of the subproject, it will first use the js/css related tags that are regularly matched to them, and then replace them. It needs to load js and run it by itself, then remove the html/head/body tags, and insert the rest into the container of the subproject as it is.

2, Micro front end scheme practice

Taking the "big data analysis" project as an example, the unique needs of customers, such as "electronic waybill" and "data filling" are separately extracted as independent sub projects.

The transformation of big data analysis project is the main application base, and the address of code warehouse is: http://192.168.1.102/zouqiongjun/big-data-web.git.

Customer defined requirements are separately used as sub application projects. Code warehouse address: http://192.168.1.102/zouqiongjun/zibo-custom-web.git.

one    Code structure of each application project

Sass base web: the main warehouse, which is mainly used to store some batch operation scripts for aggregation management warehouse, one click compilation and one click deployment.

The warehouse code structure is shown in the following figure:

 

Big data Web: the main application of big data analysis

Zibo custom Web: customer defined requirements, micro application warehouse

The sub application can run independently, but the current sub application is directly nested in the main content area of the main application, so the left menu navigation is not provided separately for the time being. This function can be extended and supplemented if necessary in the future.

two    Transformation of main application big data web

To transform an ordinary project into a qiankun main application base, three steps are required:

  (1)   Create micro application container - used to host micro applications and render and display micro applications;

  (2)   Register micro application - set micro application activation conditions, micro application address, etc;

  (3)   Start qiankun;

Note: since the routing of big data web main application adopts hash mode, the routing of sub applications should also adopt hash mode.

one point one   Install qiankun

$ yarn add qiankun # Or npm i qiankun -S

1.2. Register micro application in main application

In order to use keepAlive cache, we load micro applications manually.

After the micro application information is registered, once the url of the browser changes, the matching logic of qiankun will be automatically triggered, and all micro applications on the active rule matching will be inserted into the specified container, and the life cycle hooks exposed by the micro application will be called in turn.

In the views directory, create AppVueHash.vue as a container for sub applications. The code is as follows:

<template>
<div class="zibo-custom-web">
     <div id="zibo-custom-web" class="app-view-box"></div>
</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped>
.zibo-custom-web{
  position: relative;
}
</style>

The id attribute should be unique, and the content of the final sub application will be mounted here.

ContainerOther.vue code modification:

  <!-- Host view layer -->
        <div class="avue-view-contain" v-show="!isSearch">
          <keep-alive>
            <router-view
              class="avue-view keep-alive"
              v-if="$route.meta.keepAlive && isActiveRoute"
              v-show="!showAppVueHash"
            />
          </keep-alive>
          <router-view
            class="avue-view"
            v-if="!$route.meta.keepAlive && isActiveRoute"
            v-show="!showAppVueHash"
          />
          <AppVueHash v-show="showAppVueHash" />
        </div>

js code:

import router from "@/router/router";
import store from "@/store";
import AppVueHash from "@/views/AppVueHash.vue";
import { loadMicroApp } from "qiankun";
//Subproject routing prefix
const isChildRoute = path => website.childRoute.some(item => path.startsWith(item));
const apps = [
  {
    name: "/zibo-custom-web",
    entry: window.configs.VUE_APP_ZIBO_CUSTOM_URL,
    container: "#zibo-custom-web",
    props: { data: { store, router } },
    sandbox: {
      strictStyleIsolation: true // Open style isolation
    }
  }
];
//Control micro application manual loading
    ctrlMicroApp(path){
       if (isChildRoute(path)) {
        this.showAppVueHash = true;
        this.$nextTick(() => {
          //Manual loading
          if(!this.mounted){
            this.loadApps = apps.map(item => loadMicroApp(item))
            this.mounted=true;
          }  
        });
      } else {
        this.showAppVueHash = false;
      }

The value of the container attribute here must be consistent with the id value in the AppVueHash.vue component.

Determine whether it is a sub application according to the url address. If it is a sub application, load it manually. Otherwise, hide the sub application container and load only the router view of the main application.

Manually load micro apps when ContainerOther loads for the first time or route changes:

mounted() {
    this.init();
    setTheme(this.themeName);
    this.ctrlMicroApp(this.$route.path)
  },
  watch: {
    $route(val) {
      this.ctrlMicroApp(val.path);
},
    tagList(newVal,oldVal){
      let starts='';
      const childRoute = website.childRoute;
      childRoute.forEach((n,i)=>{
        if(i<childRoute.length-1){
          starts+=`^${n}|`;
        }else{
          starts+=`^${n}`;
        }
      })
      const patt = new RegExp(`${starts}`);
      //There was a sub application tab before
      const before = oldVal.some(item=>{
        return patt.test(item.value);
      });
      //There are sub application tabs
      const now = newVal.some(item=>{
        return patt.test(item.value);
      });
      if(before && !now){
        this.mounted=false;
        this.loadApps.forEach(app=>{
          app.unmount();  
        })
      }
    } 

Listen to the tab changes. When closing the tab, you need to uninstall the sub application.

three    qiankun subproject Zibo custom web

  1. Add the file public-path.js in the src Directory:
if (window.__POWERED_BY_QIANKUN__) {
    // eslint-disable-next-line no-undef
    __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
  }
  1. Modify the container of item initialization in index.html. Do not use #app to avoid conflicts with other items. It is recommended to write in small hump
    <div id="appVueHash"></div>
  1. Modify the entry file main.js:
// -----------Sub application micro front end start-------------------
let router = null;
let instance = null;

function render({ data = {} , container } = {}) {
  router = new VueRouter({
    routes,
  });
  instance = new Vue({
    router,
    store,
    data(){
      return {
        parentRouter: data.router,
        parentVuex: data.store,
      }
    },
    render: h => h(App),
  }).$mount(container ? container.querySelector('#appVueHash') : '#appVueHash');
}
if (!window.__POWERED_BY_QIANKUN__) {
  render();
}
//Test global variable contamination
console.log('window.a',window.a)
export async function bootstrap() {
  console.log('vue app bootstraped');
}
export async function mount(props) {
  console.log('props from main framework', props.data);
  render(props);
}
export async function unmount() {
  instance.$destroy();
  instance.$el.innerHTML = "";
  instance = null;
  router = null;
}
// -----------Sub application micro front end end-------------------

The main changes are to introduce and modify the three life cycles of publicPath file and export.

Note:

  • The publicPath value of webpack can only be modified in the entry file. The reason why it is written to a file separately and introduced at the beginning of the entry file is that this can be used by all the following codes.
  • The route file needs to export the route data instead of the instantiated route object, and the hook function of the route also needs to be moved to the entry file.
  • In the mount life cycle, you can get the data passed from the parent project. The router is used to jump to the route to the main project / other sub projects. The store is the instantiated Vuex of the parent project (other data can also be passed).
  1. Modify packaging configuration vue.config.js:
const { name } = require("./package");
module.exports = {
  outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web",
  devServer: {
    port: 9010,
    // Turn off the host check so that the micro application can be checked fetch
    disableHostCheck: true,
    // Configure the cross domain request header to solve the cross domain problem of the development environment
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
    proxy: {
      "/api": {
        //Local service interface address
        target: "http://192.168.10.112:10067", //cas
        ws: true,
        pathRewrite: {
          "^/api": "/",
        },
      },
    },
  },
   // The following configuration can fix some font file loading path problems
  chainWebpack: (config) => {
    //Package file ignored
    config.externals({
      vue: "Vue",
      "vue-router": "VueRouter",
      vuex: "Vuex",
      axios: "axios",
      "element-ui": "ELEMENT",
    });
    config
      .plugin('html')
      .tap(args => {
        args[0].name = name;
        return args
      });
    config.module
      .rule("fonts")
      .test(/.(ttf|otf|eot|woff|woff2)$/)
      .use("url-loader")
      .loader("url-loader")
      .tap((options) => ({ name: "/fonts/[name].[hash:8].[ext]" }))
      .end();
  },
  // custom webpack to configure
  configureWebpack: {
    output: {
      library: `${name}-[name]`, // The package name of the micro application, which is consistent with the micro application name registered in the main application
      libraryTarget: "umd", // Package sub applications into umd Library format
      jsonpFunction: `webpackJsonp_${name}`, //webpack Save in after packaging window Medium key,Different sub applications
    },
  },
};

There are mainly two configurations here. One is to allow cross domain, and the other is to package into umd format. Why package it in umd format? This is to let qiankun get the life cycle function of its export.

Note:   The name is obtained from package.json by default and can be customized as long as it is consistent with the name of the parent project when it is registered.

vue.config.js

  outputDir: "../sass-base-web/cicd-config/test/zibo-custom-web",

Here, after compiling my sub application project, I will package the package file under Zibo custom web in sass base web project.

  1. Route dynamic loading

You need to add a prefix to all the routes of the subproject. If you used path before, you also need to modify it. If you used name to jump, you don't need to.

  avue-router.js:

 const oRouter = {
          path: "/zibo-custom-web",
          name: "RouterView",
          component(resolve) {
            require(["@/components/RouterView.vue"], resolve);
          },

          children: [
            {
              path: path,
              component(resolve) {
                require([`../${component}.vue`], resolve);
              },
              name: name,
              meta: meta,
            },
          ],
        };
        aRouter.push(oRouter);

four    State management, communication between main application and micro application

qiankun defines the global state through initGlobalState and returns the communication method. It is recommended to use it in the main application, and the micro application obtains the communication method through props;

onGlobalStateChange: listen to the global state in the current application, and a callback will be triggered if there is a change;

setGlobalState: set the global state according to the first level attribute. Only the existing first level attribute can be modified in the micro application; In other words, you can only modify the pre-defined attributes, and the attributes added later are invalid.

Official example: publish subscribe design pattern:

Main application:

import { initGlobalState, MicroAppStateActions } from 'qiankun';
// initialization state
const actions: MicroAppStateActions = initGlobalState(state);

actions.onGlobalStateChange((state, prev) => {
  // state: Status after change; prev Status before change
  console.log(state, prev);
});
actions.setGlobalState(state);
actions.offGlobalStateChange();

Subapplications:

// From life cycle mount Obtain the communication method, use mode and master agreement
export function mount(props) {
    props.onGlobalStateChange((state, prev) => {
      // state: Status after change; prev Status before change
      console.log(state, prev);
    });
    props.setGlobalState(state);
  }

If both the main application and the sub application are vue technology stacks, data can be transferred to the sub application in the sub application, such as the store.

   props: { data: { store, router } },

five    Independent warehouse and aggregation management between applications

In the actual development, the project is stored in the company's warehouse. Taking gitLab as an example, when there are more sub applications and all of them are placed under one warehouse, it becomes very bloated and huge, which greatly increases the maintenance cost and development efficiency;

We can use the sh script. Initially, we only need to clone the main warehouse code, and then use the sh script to pull all sub application codes with one click.

Here, I will separately create a main warehouse project sass base web for compilation and packaging. The warehouse address is: http://192.168.1.102/zouqiongjun/sass-base-web.git.

Under the project root directory, create a new script/clone-all.sh file with the following contents:

# Sub service gitLab address
SUB_SERVICE_GIT=('http://192.168.1.102/zouqiongjun/big-data-web.git' 'http://192.168.1.102/zouqiongjun/zibo-custom-web.git')
SUB_SERVICE_NAME=('big-data-web' 'zibo-custom-web')

# Sub service
if [ ! -d "sub-service" ]; then
  echo 'establish sub-service catalogue...'
  mkdir sub-service
fi
echo 'get into sub-service catalogue...'
cd sub-service

# Traversal clone microservice
for i in ${!SUB_SERVICE_NAME[@]}
do
  if [ ! -d ${SUB_SERVICE_NAME[$i]} ]; then
    echo 'Clone microservice project'${SUB_SERVICE_NAME[$i]}
    git clone ${SUB_SERVICE_GIT[$i]}
  fi
done
 
echo 'End of script...'
# Clone complete

When we start the main project, if we want to use the functions of all sub applications, sub applications need to be started one by one, which is very inconvenient for both development and compilation.

Considering that npm packaging in China may fail due to network reasons, npm can use the domestic Taobao image.

Execute the command: npm config set registry https://registry.npm.taobao.org .

In this main warehouse project, we only need to install an NPM run all plug-in.

Run: yarn add NPM run all - D or npm i -D.

There is only one package.json file under the project, which is used to configure compilation and packaging commands. The code is as follows:

{
  "name": "sass-big-data-web",
  "version": "1.0.0",
  "description": "`qiankun`To achieve`vue`Front end microservices of technology stack",
  "main": "index.js",
  "scripts": {
    "clone:all": "bash ./scripts/clone-all.sh",
    "install:zibo": "cd ./sub-service/zibo-custom-web && npm install",
    "install:main": "cd ./sub-service/big-data-web && npm install",
    "install-all": "npm-run-all install:*",
    "start:zibo": "cd ./sub-service/zibo-custom-web && npm run serve ",",
    "start:main": "cd ./sub-service/big-data-web && npm run serve",
    "start-all": "npm-run-all --parallel start:*",
    "serve-all": "npm-run-all --parallel start:*",
    "build:zibo": "cd ./sub-service/zibo-custom-web && npm run build",
    "build:main": "cd ./sub-service/big-data-web && npm run build",
    "build-all": "npm-run-all --parallel build:*"
  },
  "repository": {
    "type": "git",
    "url": "http://192.168.1.102/zouqiongjun/sass-big-data-web.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "npm-run-all": "^4.1.5"
  }
}

To execute yarn clone:all, you need to use bash, jump to the sass base web directory, right-click the mouse to open the Git bash window, as shown in the following figure:

 

In this way, when we drag the code of each code warehouse to the sub service directory, as shown in the following figure:

 

After the code pull is completed, it is followed by downloading the dependency and operation of each project.

Run NPM run serve all to automatically execute the commands configured in package.json. This command will eventually execute the following three execution commands:

    "start:zibo": "cd ../zibo-custom-web && npm run serve ",
    "start:main": "cd ../big-data-web && npm run serve",

In this way, we don't need to run each project individually.

Overall running steps: the first step is to clone the main application, and then execute yarn clone: all -- > yarn install all in turn  --> yarn start-all   You can run the entire project.

Build all: you can compile the entire project.

Add the sub service directory to the. gitignore directory, because in the sass base web project, we only need to configure, compile and package, and do not really need to submit the code of all sub applications to the sass base web project. Each sub application has its own private warehouse.

six    Some considerations for sub project development

(1) all resources (pictures / audio and video, etc.) should be placed in the src directory, not in public or static. Resources are placed in the src directory, which will be processed by webpack and can be uniformly injected into publicPath. Otherwise, 404 will be in the main project.

(2) avoid css pollution. css scoped styles within components are required.

(3) clear the events bound to body, document, etc. in the unmount cycle

(4) use position: fixed with caution

In the parent project, this positioning may not be accurate and should be avoided as far as possible. There is a positioning requirement relative to the browser window. position: sticky can be used, but there will be compatibility problems (IE does not support it).

See the official website for frequently asked questions: https://qiankun.umijs.org/zh/faq

seven    deploy

one    General deployment

Both main applications and micro applications are developed and deployed independently, that is, they belong to different warehouses and services.

Scenario: main application and micro application are deployed to the same server (same IP and port)

If the number of servers is limited or cannot cross domain, the main application and micro application need to be deployed together. The common practice is that the main application is deployed in the primary directory and the micro application is deployed in the secondary / tertiary directory.

If you want to deploy a micro application in a non root directory, you need to do two things before packaging the micro application:

  • You must configure the publicPath during webpack construction as the directory name. For more information, please see the official description of webpack and the official description of vue-cli3.
  • The micro application of history routing needs to set the base, and the value is the directory name, which is used for independent access.

After deployment, pay attention to three points:

  • activeRule cannot be the same as the real access path of the micro application, otherwise the refresh of the main application page will directly become the micro application page.
  • The real access path of the micro application is the entry of the micro application, and the entry can be a relative path.
  • The last / entry path of the micro application cannot be omitted, otherwise the publicPath will be set incorrectly. For example, the access path of the subitem is http://localhost:8080/app1 , then entry is http://localhost:8080/app1/.

By configuring nginx port forwarding to directory. It is necessary to open the child to the outside world, use the corresponding port, and put the compiled utilization file into the corresponding configuration directory.

Jump to sass base web directory and execute NPM run build all. All commands starting with build: will be executed automatically:

    "build:zibo": "cd ../zibo-custom-web && npm run build",
    "build:control": "cd ../control-center && npm run build",
    "build:main": "cd ../big-data-web && npm run build",
    "build-all": "npm-run-all --parallel build:*"

The Zibo custom web directory structure is shown in the following figure:

 

Here, the sub application and the main application are deployed on the same server, and the IP and port are the same. nginx does not need additional settings.

If the sub application and the main application are deployed on the same server, but the ports are different, you need to modify the outputDir in vue.config.js. This is the path for storing the packaged and compiled code. This is not configured. By default, the code will be compiled and packaged to the current root directory and a dist directory will be generated to store the compiled code, as shown in the following figure:

 

Modify nginx.conf configuration:

 #gzip  on;
      upstream gateway { server 192.168.31.136:32067;}
     # Main application
        server {
        listen   32043;
        server_name  web;
        root  /dist;
        # Turn off port redirection
        # port_in_redirect off;
        #charset koi8-r;
        access_log /var/log/nginx/nginx.log;

        location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location ^~/api/ {  
            proxy_read_timeout 600s;
            proxy_set_header Host $host; 
            proxy_set_header X-Real-IP $remote_addr; 
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_buffering off; 
            rewrite ^/api/(.*)$ /$1 break; 
            proxy_pass http://gateway; 
            }
        }

   # Sub application
    server {
        listen   9010;
        server_name  cus_web;
        # Sub application compiled code path
        root  /zibo-custom-web;  
        # Allow cross domain
        add_header Access-Control-Allow-Origin *;
        # Turn off port redirection
        # port_in_redirect off;
        # charset koi8-r;
        access_log /var/log/nginx/nginx.log;
        location ^~/zibo-custom-web/ {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header REMOTE-HOST $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location ^~/api/ {  
            proxy_read_timeout 600s;
            proxy_set_header Host $host; 
            proxy_set_header X-Real-IP $remote_addr; 
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_buffering off; 
            rewrite ^/api/(.*)$ /$1 break; 
            proxy_pass http://gateway; 
            }
    }

two    docker nginx configuration

Here   nginx   It is mainly used for port directory forwarding and configuring the main application to access the cross domain problem of sub applications.

Use   docker   Configure deployment   nginx:

# docker-compose.yml
version: '3.1'
services:
  nginx:
    restart: always
    image: nginx
    container_name: nginx
    ports:
      - 8888:80
      - 8889:8889
      - 7100:7100
      - 7101:7101
    volumes:
      - /app/volumes/nginx/nginx.conf:/etc/nginx/nginx.conf
      - /app/volumes/nginx/html:/usr/share/nginx/html
      - /app/micro/portal:/app/micro/portal
      - /app/micro/app1:/app/micro/app1
      - /app/micro/app2:/app/micro/app2

Put the compiled main application and sub application into the corresponding data volume mounting directory, such as the main application  / app/micro/portal.
Similarly, the configured   nginx.conf   Put the file in the specified data volume mount directory and use   docker-compose up -d   Just start.

  nginx   Port directory forwarding configuration:

# nginx.conf
user  nginx;
worker_processes  1;
error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;

events {
    worker_connections  1024;}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  65;

    #gzip  on;
    include /etc/nginx/conf.d/*.conf;
    server {
      listen    8889;
      server_name 192.168.2.192;
      location / {
        root /app/micro/portal;
        index index.html;
        try_files $uri $uri/ /index.html;
      }
    }
    server {
      listen    7100;
      server_name 192.168.2.192;

      # Configure cross domain access. Here is a wildcard. If the production environment is strict, you can specify the main application 192.168.2.192:8889
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
      add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
      location / {
        root /app/micro/app1;
        index index.html;    
        try_files $uri $uri/ /index.html;
      }
    }
    server {
      listen    7101;
      server_name 192.168.2.192;
     
      # Configure cross domain access. Here is a wildcard. If the production environment is strict, you can specify the main application 192.168.2.192:8889
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
      add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
      
      location / {
        root /app/micro/app2;
        index index.html;   
        try_files $uri $uri/ /index.html;
      }
    }}

To deploy to production, you need to modify Vue in big data web / public / util / config.js_ APP_ ZIBO_ CUSTOM_ URL configuration item:

(function() {
  window.configs = {
    VUE_APP_CASLOGINURL: "http://192.168.1.99:32080/cas", //cas Login address
    VUE_APP_REDIRECTURL: "http://192.168.51.61:8888/big-data/", //Front end deployment address
    VUE_APP_SOCKET: "ws://192.168.31.136:32061", //websocket address'
    VUE_APP_AMAPURLPREFIX: "https://webapi.amap.com", //Gaode map address
    VUE_APP_ZIBO_CUSTOM_URL:"http://localhost:9010",//Custom micro app address
    //================================================

    VUE_APP_AMAPKEY: "xxxxxx" //Gaode key
  };
})();
 

Here, config.js is external to the configuration file and does not need to be compiled.

eight    summary

Although the qiankun framework supports each sub application to use different technical frameworks, the sub applications need to be modified accordingly, and various unpredictable errors always appear from time to time in other technology stacks. Once there is a problem, we need to modify the code. Therefore, if they are all vue technology stacks, it is recommended to use qiankun as the micro front end.

If the project of a third-party company is accessed, we need to consider whether to use iframe as appropriate because their code is not under our control.

Posted by Basdub on Thu, 28 Oct 2021 22:41:34 -0700