1. 程式人生 > 其它 >MicroApp樣例搭建【Vue】

MicroApp樣例搭建【Vue】

樣例程式碼可以點選這裡下載,搭建流程如下

專案建立

專案由 vue 的官方腳手架建立,基專案 base 和子專案 app_first、app_second

vue create base

vue create app_first
vue create app_second

基專案修改

新增本地執行配置檔案 vue.config.js

module.exports = {
    devServer: {
        host: 'localhost'
        , port: 3000
    }
}

安裝 micro-app 外掛

npm install @micro-zoe/micro-app --save

新增 micro/index.js 檔案

import microApp from '@micro-zoe/micro-app'
import * as config from './config'

// 啟用 micro
microApp.start({
    preFetchApps: config.MICRO_APPS //載入子專案
    , globalAssets: config.GLOBAL_ASSETS // 載入全域性資源
})

新增 micro/config.js 檔案

// 子應用字首
export const CHILD_PREFIX = 'app'

// 子應用地址
export const MICRO_APPS = [
    { name: 'first-child', url: `http://localhost:3001/` }
    , { name: 'second-child', url: `http://localhost:3002/` }
]

// 全域性資源
export const GLOBAL_ASSETS = {
    js: []
    , css: []
}

修改入口檔案 main.js,引入 micro-app 配置

import './micro'
...

修改 App.vue 檔案

<template>
    <div>
        <!--路由連結-->
        ...
    </div>
    <div>
        <micro-app 
            v-if="isChild" 
            v-bind="micro" 
            destory 
            @datachange='handleDataChange'></micro-app>
        <router-view v-else></router-view>
    </div>
</template>

<script>
import { MICRO_APPS, CHILD_PREFIX } from './micro/config.js'
    
export default {
    ...
    , data(){
    	return {
    	    ...
            , isChild: false	// 是否是子模組
            , micro: {
    		url: '' 	// 子應用地址,不包含路由地址
    		, key: ''	// Vue 標籤的 key 值,用於不同子模組間的切換時,元件重新渲染
    		, name: ''	// 子模組名稱,值唯一
    		, data: {}	// 需要傳入子模組的資料
    		, baseroute: ''	// 子模組路由地址
            }
	}
    }
    , watch: {
        $route (val){
            // 監聽路由變化,改變子模組渲染
            this.changeChild(val)
        }
    }
    , created () {
        this.changeChild(this.$route)
    }
    , methods: {
        ...
	, getAppUrl (name) { // 獲取子模組 url 和 name
            return MICRO_APPS.find(app => app.name === name) || {}
	}
	, changeChild (route) { // 修改子檢視顯示
            let path = route.path.toLowerCase()
		, paths = path.split('/')

            // 判斷是否為子模組,子模組有固定的字首
            this.isChild = paths.length > 2 && paths[1] === CHILD_PREFIX

            if (this.isChild) {
                let app = this.getAppUrl(paths[2])

                this.micro = {
                    ...app
                    , data: { name: route.name } // 根據路由和子專案跳轉方式,傳入對應引數
                    , key: `${app.name}`
                    , baseroute: `/${CHILD_PREFIX}/${paths[2]}`
                }
            }
	}
	, handleDataChange (event) { // 獲取子路由傳遞的資訊
            let data = event.detail.data
            if(data.route) this.$router.push({ name: data.route.name })
	}
    }
}
</script>

修改路由檔案 router/index.js

...
import { CHILD_PREFIX } from '@/micro/config.js'

const routes = [
    ...
    , { // app_first 專案路由
        path: `/${CHILD_PREFIX}/first-child`
	, name: 'FirstChild'
	, children: [
            {
                path: 'home'
                , name: 'FirstHome'
            }
            , {
                path: 'about'
                , name: 'FirstAbout'
            }
        ]
    }
    , { // app_second 專案路由
	path: `/${CHILD_PREFIX}/second-child`
	, name: 'SecondChild'
	, children: [
            {
                path: 'home'
                , name: 'SecondHome'
            }
            , {
                path: 'about'
                , name: 'SecondAbout'
            }
	]
    }
]

...

子專案修改

新增本地執行配置檔案 vue.config.js,設定允許跨域訪問

module.exports = {
    devServer: {
        host: 'localhost'
        , port: 3001
        , headers: { // 設定本地執行的跨域許可權
            'Access-Control-Allow-Origin': '*',
        }
    }
}

新增 micro/index.js 檔案

// 設定 webpack 的公共路徑
__webpack_public_path__ = window.__MICRO_APP_PUBLIC_PATH__ || '/'

入口檔案修改 mian.js

import './micro'
...

let app

/**
 * 掛載函式
 */
function mount () {
    app = new Vue({
        el: '#app'
        , router
        , render: function (h) { return h(App) }
    })
}

/**
 * 解除安裝函式
 */
function unmount () {
    app.$destroy()
    app.$el.innerHTML = ''
    app = null
}

// 微前端環境下,註冊mount和unmount方法
if (window.__MICRO_APP_ENVIRONMENT__)
    window[`micro-app-${window.__MICRO_APP_NAME__}`] = { mount, unmount }
else
    mount()

修改 App.vue 檔案

<template>
    <div id="app">
        <div id="nav">
            <router-link :to="`${prefix}/home`">Home</router-link> |
            <router-link :to="`${prefix}/about`">About</router-link> |
            <button @click="goto('SecondHome')">SecondHome</button> |
            <button @click="goto('SecondAbout')">SecondAbout</button>
        </div>
        <router-view />
    </div>
</template>

<script>
export default {
    ...
    , methods: {
        ...
        , dataListener (data) {
            // 不判斷時會報一個“冗餘導航【NavigationDuplicated】”的異常
            if (data.name !== this.$route.name)
                this.$router.push({ name: data.name })
        }
        , goto (name) {
            // 向基專案傳送資料
            window.microApp.dispatch({ route: { name } })
        }
    }
    , created () {
        // 繫結資料【data屬性】監聽事件
        window.microApp && window.microApp.addDataListener(this.dataListener)
    }
    , destroyed () {
        // 移除資料【data屬性】監聽事件
        window.microApp && window.microApp.removeDataListener(this.dataListener)
    }
}
</script>

修改路由檔案 router/index.js

...

const routes = [
    {
        path: window.__MICRO_APP_BASE_ROUTE__ || '/' // 根據專案執行的不同環境,設定路徑的字首
        , name: 'Home'
        , redirect: { name: 'FirstHome' }
        , component: () => import('../views/Empty.vue') // Empty.vue 是一個只包含 router-view的頁面,用於渲染 children
        , children: [
            ...
        ]
    }
]

...

專案啟動

分別進入專案資料夾,在 CMD 下執行 npm run serve,啟動專案,訪問 localhost:3000 檢視完整的專案,也可以開啟 localhost:3001 或者 localhost:3002 訪問單個子專案

一些問題處理

  • 公共模組程式碼

    可以將公共程式碼單獨建立一個倉庫,在各個專案中以子模組的形式引入到專案中

  • Nginx 部署

    微前端在部署到多個地址時,可以通過 nginx 的反向代理,把子專案的地址代理到主專案地址下,這樣可以是主專案和子專案使用相同的 storage 儲存

server {
    listen       3000;
    server_name  localhost;

    location / {
        root   D:/base/dist/;
        index  index.html index.htm;
        try_files  $uri $uri/ /index.html;
    }

    # 代理子專案
    location /first_child/ {
        proxy_pass  http://localhost:3001/;
    }
}
  
# 子專案訪問埠
server {
    listen       3001;
    server_name  localhost;

    # 設定跨域訪問許可權
    add_header Access-Control-Allow-Origin *;

    location / {
        root  D:/first_child/dist/;
        index  index.html index.htm;
        try_files  $uri $uri/ /index.html;
    }
 }

原文連結:MicroApp樣例搭建【Vue】