Vue + qiankun 快速實現前端微服務

本文介紹 Vue 項目如何實現前端微服務html

1、前言

什麼是微前端

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently. -- Micro Frontends

微前端是一種多個團隊經過獨立發佈功能的方式來共同構建現代化 web 應用的技術手段及方法策略。前端

更多關於微前端的相關介紹,推薦你們能夠去看這幾篇文章:vue

qiankun

qiankun 是螞蟻金服開源的一套完整的微前端解決方案。具體描述可查看 文檔 和 Githubwebpack

下面將經過一個微服務Demo 介紹 Vue 項目如何接入 qiankun,代碼地址:micro-front-vue)git

2、配置主應用

  1. 使用 vue cli 快速建立主應用;
  2. 安裝 qiankun
$ yarn add qiankun # 或者 npm i qiankun -S
  1. 調整主應用 main.js 文件:具體以下:
import Vue from "vue"
import App from "./App.vue"
import router from "./router"

import { registerMicroApps, setDefaultMountApp, start } from "qiankun"
Vue.config.productionTip = false
let app = null;
/**
 * 渲染函數
 * appContent 子應用html內容
 * loading 子應用加載效果,可選
 */
function render({ appContent, loading } = {}) {
    if (!app) {
        app = new Vue({
            el: "#container",
            router,
            data() {
                return {
                    content: appContent,
                    loading
                };
            },
            render(h) {
                return h(App, {
                    props: {
                        content: this.content,
                        loading: this.loading
                    }
                });
            }
        });
    } else {
        app.content = appContent;
        app.loading = loading;
    }
}

/**
 * 路由監聽
 * @param {*} routerPrefix 前綴
 */
function genActiveRule(routerPrefix) {
    return location => location.pathname.startsWith(routerPrefix);
}

function initApp() {
    render({ appContent: '', loading: true });
}

initApp();

// 傳入子應用的數據
let msg = {
    data: {
        auth: false
    },
    fns: [
        {
            name: "_LOGIN",
            _LOGIN(data) {
                console.log(`父應用返回信息${data}`);
            }
        }
    ]
};
// 註冊子應用
registerMicroApps(
    [
        {
            name: "sub-app-1",
            entry: "//localhost:8091",
            render,
            activeRule: genActiveRule("/app1"),
            props: msg
        },
        {
            name: "sub-app-2",
            entry: "//localhost:8092",
            render,
            activeRule: genActiveRule("/app2"),
        }
    ],
    {
        beforeLoad: [
            app => {
                console.log("before load", app);
            }
        ], // 掛載前回調
        beforeMount: [
            app => {
                console.log("before mount", app);
            }
        ], // 掛載後回調
        afterUnmount: [
            app => {
                console.log("after unload", app);
            }
        ] // 卸載後回調
    }
);

// 設置默認子應用,與 genActiveRule中的參數保持一致
setDefaultMountApp("/app1");

// 啓動
start();
  1. 修改主應用 index.html 中綁定的 id ,需與 el  綁定 dom 爲一致;
  2. 調整 App.vue 文件,增長渲染子應用的盒子:
<template>
  <div id="main-root">
    <!-- loading -->
    <div v-if="loading">loading</div>
    <!-- 子應用盒子 -->
    <div id="root-view" class="app-view-box" v-html="content"></div>
  </div>
</template>

<script>
export default {
  name: "App",
  props: {
    loading: Boolean,
    content: String
  }
};
</script>
  1. 建立 vue.config.js 文件,設置 port :
module.exports = {
    devServer: {
        port: 8090
    }
}

3、配置子應用

  1. 在主應用同一級目錄下快速建立子應用,子應用無需安裝 qiankun
  2. 配置子應用 main.js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import './public-path';

Vue.config.productionTip = false;

let router = null;
let instance = null;

function render() {
    router = new VueRouter({
        base: window.__POWERED_BY_QIANKUN__ ? '/app1' : '/',
        mode: 'history',
        routes,
    });

    instance = new Vue({
        router,
        render: h => h(App),
    }).$mount('#app');
}

if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

export async function bootstrap() {
    console.log('vue app bootstraped');
}

export async function mount(props) {
    console.log('props from main app', props);
    render();
}

export async function unmount() {
    instance.$destroy();
    instance = null;
    router = null;
}
  1. 配置 vue.config.js
const path = require('path');
const { name } = require('./package');

function resolve(dir) {
    return path.join(__dirname, dir);
}

const port = 8091; // dev port

module.exports = {
  /**
   * You will need to set publicPath if you plan to deploy your site under a sub path,
   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
   * then publicPath should be set to "/bar/".
   * In most cases please use '/' !!!
   * Detail: https://cli.vuejs.org/config/#publicpath
   */
    outputDir: 'dist',
    assetsDir: 'static',
    filenameHashing: true,
    // tweak internal webpack configuration.
    // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
    devServer: {
        // host: '0.0.0.0',
        hot: true,
        disableHostCheck: true,
        port,
        overlay: {
            warnings: false,
            errors: true,
        },
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
    // 自定義webpack配置
    configureWebpack: {
        resolve: {
            alias: {
                '@': resolve('src'),
            },
        },
        output: {
            // 把子應用打包成 umd 庫格式
            library: `${name}-[name]`,
            libraryTarget: 'umd',
            jsonpFunction: `webpackJsonp_${name}`,
        },
    },
};

其中有個須要注意的點:github

  1. 子應用必須支持跨域:因爲 qiankun 是經過 fetch 去獲取子應用的引入的靜態資源的,因此必需要求這些靜態資源支持跨域;
  2. 使用 webpack 靜態 publicPath 配置:能夠經過兩種方式設置,一種是直接在 mian.js 中引入 public-path.js 文件,一種是在開發環境直接修改 vue.config.js:
{
  output: {
    publicPath: `//localhost:${port}`;
  }
}

public-path.js 內容以下:web

if (window.__POWERED_BY_QIANKUN__) {
  // eslint-disable-next-line no-undef
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
至此,Vue 項目的前端微服務已經簡單完成了。

可是在實際的開發過程當中,並不是如此簡單,同時還存在應用間跳轉、應用間通訊等問題。vue-router


代碼、文章 持續更新中...vue-cli

相關文章
相關標籤/搜索