微前端 qiankun + Vite + Vue3 + Vue2

qiankun 是什么

qiankun 是基于 single-spa 的微前端實(shí)現(xiàn)庫湃鹊,可以幫助大家更快速的構(gòu)建一個(gè)前端微架構(gòu)體系桃移。

微前端是什么

官方給出的概念是:微前端是一種多個(gè)團(tuán)隊(duì)通過獨(dú)立發(fā)布功能的方式來共同構(gòu)建現(xiàn)代化 web 應(yīng)用的技術(shù)手段及方法策略君旦。簡(jiǎn)單理解就是一個(gè)大型項(xiàng)目中,有一個(gè)主應(yīng)用土榴,N 個(gè)子應(yīng)用家坎,各個(gè)應(yīng)用之間可以獨(dú)立開發(fā)疮茄,獨(dú)立運(yùn)行,獨(dú)立部署员咽。

為什么要用微前端

我們應(yīng)該都有這樣的經(jīng)歷毒涧,一個(gè)項(xiàng)目一直在更新迭代,參與的人也越來越多骏融,代碼也越來越多链嘀,導(dǎo)致項(xiàng)目越來越不好管理,打包速度越來越慢档玻,打包體積越來越大怀泊,部署不方便。尤其是在有一個(gè)很小的需求要更新時(shí)误趴,我們需要重新打包部署整個(gè)項(xiàng)目霹琼,就很頭大。所以我們就需要微前端凉当,把一個(gè)單一的應(yīng)用枣申,轉(zhuǎn)換為多個(gè)可以獨(dú)立開發(fā)、測(cè)試看杭、部署的小應(yīng)用忠藤。但用戶是無感知的,依舊認(rèn)為是一個(gè)產(chǎn)品楼雹。

開始搭建微前端的主應(yīng)用(基座)

安裝 qiankun

yarn add qiankun # 或者 npm i qiankun -S

在主應(yīng)用中注冊(cè)微應(yīng)用

我們?cè)?src 文件夾下新建一個(gè) qiankun/index.ts 模孩,用來放我們的 qiankun 的配置信息

// src/qiankun/index.ts
import {registerMicroApps, start} from 'qiankun';

registerMicroApps([
    {
        name: 'qiankun-demo-b', // 子應(yīng)用的注冊(cè)名稱,即子應(yīng)用 package.json 中的 name 
        entry: '//localhost:5174', // 子應(yīng)用的啟動(dòng)地址
        container: '#app-b',  // 承載子應(yīng)用的容器贮缅,在主應(yīng)用中榨咐,有一個(gè) ID 為 app-b 的 div,用來承載子應(yīng)用
        activeRule: '/about',  // 點(diǎn)擊哪個(gè)路由會(huì)進(jìn)入子應(yīng)用
    },
    /*
    * 比如谴供,我在 app.vue 文件中注冊(cè)了兩個(gè)路由
    * <template>
          <nav>
            <RouterLink to="/">Home</RouterLink>
            <RouterLink to="/about">About</RouterLink>
          </nav>
        
          <RouterView />
        </template>
    * 那么這個(gè) activeRule: '/about' 對(duì)應(yīng)的就是 <RouterLink to="/about">About</RouterLink> 這個(gè)路由
    * 之后块茁,我在 about.vue 這個(gè)文件中,添加一個(gè)承載子應(yīng)用的 div,那么這個(gè) container: '#app-b' 對(duì)應(yīng)的就是 <div id="app-b"></div> 這個(gè) div
    * <template>
          <div class="about">
            <h1>This is an about page 111</h1>
            <div id="app-b"></div>
          </div>
        </template>
    * 有多個(gè)子應(yīng)用数焊,可以按這種方式來配置多個(gè)
    * */
    {
        name: 'qiankun-demo-d',
        entry: '//localhost:8080',
        container: '#app-d',
        activeRule: '/car',
    }
]);

start();

在 main.ts 中引入

// 引入qiankun
import './qiankun/index'

微應(yīng)用

Vue3 + Vite

我們先來看 Vue 微應(yīng)用永淌,Vue 微應(yīng)用有一個(gè)點(diǎn)需要注意的就是 Vite , qiankun 與 Vite 不能一起使用佩耳,所以需要額外安裝一個(gè)插件仰禀,以下是使用 Vite 時(shí) qiankun 的配置

npm install vite-plugin-qiankun

微應(yīng)用需要在自己的入口 js 導(dǎo)出 bootstrapmount蚕愤、unmount 三個(gè)生命周期鉤子答恶,以供主應(yīng)用在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用。
我們來修改子應(yīng)用里的 main.ts 文件

// main.ts
import {createApp} from 'vue'
import App from './App.vue'
import router from './router'

import './assets/main.css'

import {renderWithQiankun, qiankunWindow} from 'vite-plugin-qiankun/dist/helper'

let instance: any = null
function render(props: any = {}) {
    const { container } = props
    instance = createApp(App)
    instance.use(router)
    instance?.mount(container ? container.querySelector('#app') : '#app')
    console.log('開始加載相關(guān)內(nèi)容')
}
/*
* bootstrap :
* 只會(huì)在微應(yīng)用初始化的時(shí)候調(diào)用一次萍诱,下次微應(yīng)用重新進(jìn)入時(shí)會(huì)直接調(diào)用 mount 鉤子悬嗓,不會(huì)再重復(fù)觸發(fā) bootstrap。
* 通常我們可以在這里做一些全局變量的初始化裕坊,比如不會(huì)在 unmount 階段被銷毀的應(yīng)用級(jí)別的緩存等包竹。
* mount :
*  應(yīng)用每次進(jìn)入都會(huì)調(diào)用 mount 方法,通常我們?cè)谶@里觸發(fā)應(yīng)用的渲染方法
* unmount :
*  應(yīng)用每次 切出/卸載 會(huì)調(diào)用的方法籍凝,通常在這里我們會(huì)卸載微應(yīng)用的應(yīng)用實(shí)例
* update :
* 可選生命周期鉤子周瞎,僅使用 loadMicroApp 方式加載微應(yīng)用時(shí)生效
* */
renderWithQiankun({
    mount(props: any) {
        // 應(yīng)用每次進(jìn)入都會(huì)調(diào)用 mount 方法,所以我們?cè)谶@里初始化一些內(nèi)容
        render(props)
    },
    bootstrap() {
        console.log('微應(yīng)用初始化的時(shí)候調(diào)用一次')
    },
    update() {
        console.log('update')
    },
    unmount(props: any) {
        console.log('unmount:應(yīng)用每次 切出/卸載 會(huì)調(diào)用的方法', props)
        instance.unmount()
        instance._container.innerHTML = ''
        instance = null
    }
})
/*
* 通過 qiankunWindow.__POWERED_BY_QIANKUN__ 判斷是不是 qiankun 渲染的饵蒂,如果不是 qiankun 渲染的声诸,需要調(diào)用以下 render 方法來初始化一些內(nèi)容
* */
if (!qiankunWindow.__POWERED_BY_QIANKUN__) {
    console.log('并不是qiankun渲染')
    render()
}

打包配置修改,需要配置微應(yīng)用的名字與端口號(hào)退盯,使其與主應(yīng)用配置的微應(yīng)用保持一致

 // vite.config.js
import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import qiankun from 'vite-plugin-qiankun'

export default defineConfig({
    plugins: [
        vue(),
        qiankun('vue-app', { // 微應(yīng)用名字彼乌,與主應(yīng)用注冊(cè)的微應(yīng)用名字保持一致
            useDevMode: true
        })
    ],
    server: {
        port: 5174  // 微應(yīng)用端口號(hào),與主應(yīng)用注冊(cè)的微應(yīng)用保持一致
    },
    resolve: {
        alias: {
            '@': fileURLToPath(new URL('./src', import.meta.url))
        }
    }
})

Vue3 不使用 Vite

這里我們就不需要安裝任何插件了渊迁,只需在微應(yīng)用的入口文件導(dǎo)出 bootstrap慰照、mountunmount 三個(gè)生命周期鉤子琉朽,以供主應(yīng)用在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用就可以了毒租。
同樣還是修改 main.ts 文件,這里的思路和 Vue3 + Vite 的是一樣的箱叁,只是寫法略微不同而已

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'


let app = null;

function render(props = {}) {
    const { container } = props;
    app = createApp(App);
    app
        .use(store)
        .use(router)
        .mount(container ? container.querySelector("#app") : "#app");
}

// 獨(dú)立運(yùn)行時(shí)
// 這里和 Vue3 + Vite 不太一樣墅垮,是通過 window.__POWERED_BY_QIANKUN__ 來判斷是否是 qiankun 渲染的
if (!window.__POWERED_BY_QIANKUN__) {
    console.log('獨(dú)立運(yùn)行')
    render();
}

export async function bootstrap() {
    console.log('微應(yīng)用初始化的時(shí)候調(diào)用一次');
}
export async function mount(props) {
    console.log("mount", props);
    render(props);
}
export async function unmount() {
    app.unmount();
}

打包配置修改,需要配置微應(yīng)用的名字與端口號(hào)蝌蹂,使其與主應(yīng)用配置的保持一致

 // vue.config.ts
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package');
module.exports = defineConfig({
    transpileDependencies: true,
    publicPath: "http://localhost:8080/",
    devServer: {
        port: 8080, // 微應(yīng)用端口號(hào)噩斟,與主應(yīng)用注冊(cè)的微應(yīng)用保持一致
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
    configureWebpack: {
        output: {
            library: `${name}-[name]`,
            libraryTarget: 'umd', // 把微應(yīng)用打包成 umd 庫格式
        },
    },

})

Vue2

Vue2 和 Vue3 中不使用 Vite 是一樣的曹锨,唯一的區(qū)別就是 Vue2 和 Vue3 的語法不太一樣孤个,直接上代碼

// main.js 
import Vue from 'vue';
import VueRouter from 'vue-router';
import App from './App.vue';
import routes from './router';
import store from './store';

Vue.config.productionTip = false;

let router = null;
let instance = null;
function render(props = {}) {
    const { container } = props;
    router = new VueRouter({
        base: window.__POWERED_BY_QIANKUN__ ? '/app-vue/' : '/',
        mode: 'history',
        routes,
    });

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

// 獨(dú)立運(yùn)行時(shí)
if (!window.__POWERED_BY_QIANKUN__) {
    render();
}

export async function bootstrap() {
    console.log('[vue] vue app bootstraped');
}
export async function mount(props) {
    console.log('[vue] props from main framework', props);
    render(props);
}
export async function unmount() {
    instance.$destroy();
    instance.$el.innerHTML = '';
    instance = null;
    router = null;
}

打包配置修改

 // vue.config.js
const { defineConfig } = require('@vue/cli-service')
const { name } = require('./package');
module.exports = defineConfig({
    transpileDependencies: true,
    publicPath: "http://localhost:8080/",
    devServer: {
        port: 8080,
        headers: {
            'Access-Control-Allow-Origin': '*',
        },
    },
    configureWebpack: {
        output: {
            library: `${name}-[name]`,
            libraryTarget: 'umd', // 把微應(yīng)用打包成 umd 庫格式
        },
    },

})

這里只介紹了子應(yīng)用為 Vue 的情況,當(dāng)然我們也可以創(chuàng)建一個(gè) React 或者 Angular 的子應(yīng)用沛简,其配置方法 qiankun 中都有示例

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末齐鲤,一起剝皮案震驚了整個(gè)濱河市斥废,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌给郊,老刑警劉巖牡肉,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異淆九,居然都是意外死亡统锤,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門炭庙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饲窿,“玉大人,你說我怎么就攤上這事焕蹄∮庑郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵腻脏,是天一觀的道長(zhǎng)鸦泳。 經(jīng)常有香客問我,道長(zhǎng)永品,這世上最難降的妖魔是什么做鹰? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮鼎姐,結(jié)果婚禮上誊垢,老公的妹妹穿的比我還像新娘。我一直安慰自己症见,他們只是感情好喂走,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谋作,像睡著了一般芋肠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上遵蚜,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天帖池,我揣著相機(jī)與錄音,去河邊找鬼吭净。 笑死睡汹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寂殉。 我是一名探鬼主播囚巴,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了彤叉?” 一聲冷哼從身側(cè)響起庶柿,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎秽浇,沒想到半個(gè)月后浮庐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柬焕,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年审残,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斑举。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡维苔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出懂昂,到底是詐尸還是另有隱情介时,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布凌彬,位于F島的核電站沸柔,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铲敛。R本人自食惡果不足惜褐澎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伐蒋。 院中可真熱鬧工三,春花似錦、人聲如沸先鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽焙畔。三九已至掸读,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宏多,已是汗流浹背儿惫。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留伸但,地道東北人肾请。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像更胖,于是被迫代替她去往敵國(guó)和親铛铁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子隔显,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容