從0到1落地微前端架構 001【學習筆記】

微前端

js 隔離
css 隔離
元素隔離
生命週期
預加載
數據通信
應用跳轉
多層嵌套


說明

  • 使用的是 Mermaid 的 flowchart 語法,Markdown 渲染器如 Typora、VitePress、一些 Git 平台都支持。
  • 保留了:
  • 基座應用 main-vue3
  • 各子應用:child-nuxt2-homechild-vue2-jobchild-vue3-enterprisechild-react18-about
  • 框架的核心邏輯,如 JS 隔離、樣式隔離、生命週期、應用通信、虛擬路由等
  • 右側的初始化流程

◆ 多種前沿技術棧
◆ 多項目實操,一人分飾幾角
◆ 微前端應用場景、落地方案
◆ 巨石應用開發流程
◆ 架構思維、架構能力
◆ 打造企業級微前端應用

兩個問題

  • 甚麼是微前端
  • 背景 屎山代碼(開發、運行、打包,但又不能將其廢掉,還要把需求增量到項目中)【巨石應用】
  • 基本概念 最早出現在 2016 年(借鑒了微服務的架構)
  • 核心思想 容器應用(主應用)子應用(微應用)
  • 使用場景
    • 增量升級 減少衝突 提高效率
    • 靈活性,(技術棧無關)可以使用不同的構建工具
    • 穩定性 各微應用各司其職,聚合平台
    • 獨立性 獨立開發、測試、部署
  • iframe single-spa qiankun micro-app
    • <iframe src="https://www.example.com" sandbox></iframe> 簡單易用,天然沙箱(完全隔離),隔離太完美,刷新即丟失(白屏時間長加載速度慢)
  • single-spa 是最早的微前端框架(單頁面微前端模式),在基座上維護一個基座路由表,微前端框架鼻祖,改造成本大,沙箱不完美,應用通信能力差(單頁面),不支持 esmodule,所以也不支持 vite

    ```js
    // 1. 註冊
    // 2. 加載
    import { registerApplication } from 'single-spa';

    registerApplication({
    name: 'app',
    app: () => {
    loadScripts('./chunk-a.js');
    loadScripts('./chunk-b.js');
    return loadScripts('./entry.js');
    },
    });

    singleSpa.start();
    ```

  • Qiankun 基本 single-spa 也有提升

    • 它是通過 html entry
    • 更完備的沙箱方案
    • 適配成本高,同樣對基座和子應用做一些改動,不支持 vite
  • Micro-app 京東技術團隊

    • 低侵入性(適配成本低),開箱即用
    • 文檔易讀
    • 更好的兼容性(支持 webpack,vite)
  • 為甚麼要學習

現代微前端架構理論

之前通過 nginx 配置不同的入口來實現

  1. 團隊自治 跨多團隊合作開發睏難
  2. 核心思想 開發、部署成本
  3. 場景落地 系統的漸進性、動態性
graph LR
  主分支[主分支] -->|git倉庫| 分支1
  主分支 --> 分支2
  主分支 --> 分支3
  主分支 --> 分支4

  分支1 --> 團隊1
  團隊1 -->|commit| 趙 --> 錢 --> 孫

  分支2 --> 團隊2
  團隊2 -->|commit| 李 --> 周 --> 吳

  分支3 --> 團隊3
  團隊3 -->|commit| 鄭 --> 王 --> 馮

  分支4 --> 團隊4
  團隊4 -->|commit| 陳 --> 褚 --> 衛

每個倉庫都會進行獨立的部署

graph LR
  主分支[主分支] -->|git倉庫| 團隊1倉庫
  主分支 --> 團隊2倉庫
  主分支 --> 團隊3倉庫
  主分支 --> 團隊4倉庫

  團隊1倉庫 -->|commit| 趙 --> 錢 --> 孫
  團隊2倉庫 -->|commit| 李 --> 周 --> 吳
  團隊3倉庫 -->|commit| 鄭 --> 王 --> 馮
  團隊4倉庫 -->|commit| 陳 --> 褚 --> 衛

獨立開發(每個應用都是一個獨立的應用)

技術選型

微前端框架技術框架無關,我們可以選擇任何前端的技術框架

微前端應用 = 微前端框架 + JS 框架 + UI 框架 + 構建工具

  • 微前端框架:Micro-app
  • JS 框架:Vue3、Vue2、Nuxt2、React18
  • UI 框架:Element-ui、Element-plus
  • 構建工具:Webpack5、Vite4、Vue-cli5

整體架構思路為 CustomElement + HTMLEntry:

  • micro-app 標籤:上可以設置各種配置,比如開啓 iframe 沙箱、開啓 SSR 模式、開啓 keep-alive 模式、關閉沙箱、數據通信。
  • HTMLEntry:就是以 HTML 文件作為入口地址進行渲染。

主要功能:

生命週期、環境變量、虛擬路由、js 沙箱、樣式隔離、元素隔離、數據通信等等

生命週期

  • created<micro-app> 標籤初始化後,加載資源前觸發。
  • beforemount:加載資源完成後,開始渲染之前觸發。
  • mounted:子應用渲染結束後觸發。
  • unmount:子應用卸載時觸發。

環境變量

  • __MICRO_APP_PUBLIC_PATH__
  • __MICRO_APP_BASE_ROUTE__

虛擬路由系統

通過虛擬路由系統,我們可以方便地進行導航守衛、跨應用的跳轉,提升開發效率,並且子應用運行在這套虛擬路由系統中,和主應用的路由進行隔離,避免相互影響,如:

  • 主應用控制子應用跳轉
  • 子應用控制主應用跳轉
  • 子應用控制其它子應用跳轉

js 沙箱

確保子應用之間 全局變量/事件不衝突

樣式隔離

確保子應用之間樣式互相不干擾

.test {
  color: red;
}

/* 轉換為 */
micro-app[name='xxx'] .test {
  color: red;
}

元素隔離

元素隔離的概念來自 ShadowDom,即 ShadowDom 中的元素可以和外部的元素重復但不會衝突。micro-app 模擬實現了類似 ShadowDom 的功能:

  • 元素不會逃離 <micro-app> 元素邊界。
  • 子應用只能對自身的元素進行增、刪、改、查的操作。

通信

主子通信
子應用全局通信

其它能力

預加載,緩存等

系統架構

graph TD
    A[基座應用 main-vue3] -->|登錄| B[micro-app 框架邏輯]
    B --> C[JS 隔離]
    B --> D[樣式隔離]
    B --> E[元素隔離]
    B --> F[生命週期]
    B --> G[應用通信]
    B --> H[虛擬路由系統]
    B --> I[預加載]
    B --> J[資源地址補全]
    B --> K[...]

    B --> L[子應用 child-nuxt2-home]
    B --> M[子應用 child-vue2-job]
    B --> N[子應用 child-vue3-enterprise]
    B --> O[子應用 child-react18-about]

    P[初始化 micro-app] --> Q[嵌入子應用]
    Q --> R[通用組件]
    R --> S[統一鑒權]

1-1.png

4 個子應用和 1 個主應用

nvm 對 nodejs 版本管理

甚麼是 nvm

nvm 是 node 的包管理工具,它可以幫助我們在不同的項目環境中使用不同的 node 版本,所以在啓用不同項目時,可能遇到報錯。

例如:如果我們本次教程的所使用到的 nuxt3 和 vite 搭建不同的項目,就是依賴於不同的 node 環境。

  • nuxt3 依賴的 node 版本 >= v14.16.0
  • vite >= 12.0.0

所以我們的電腦里需要配置兩種 node,在我們當前的項目中使用對應的 node 環境,如何使得不同版本的 node 共存系統呢,請看下文。

nvm 的安裝

下載

下載,選擇某一個版本的 nvm,安裝 nvm-setup.zip。

主子應用的功能分配

主應用:基座(main-vue3)

功能:拿到 token 然後派發到各個子應用

  • 登錄 /api/auth/login POST
  • 登出 /api/auth/logout POST

接口說明:

  • 登錄:傳入賬號和密碼,返回 token。
  • 登出:清除 token。
// POST /api/auth/login
{
  "username": "test",
  "password": "123456"
}
// 返回
{
  "token": "mocked-token-123"
}

子應用:首頁(child-nuxt2-home)

功能:

  • 首頁列表 /api/home/list GET

mock 示例:

// GET /api/home/list
[
  { "id": 1, "title": "首頁內容一" },
  { "id": 2, "title": "首頁內容二" }
]

子應用:找工作(child-vue2-job)

功能:

  • 職位列表 /api/job/list GET
  • 職位詳情 /api/job/detail/:id GET

mock 示例

// GET /api/job/list
[
  { "id": 101, "title": "前端開發", "company": "阿里巴巴" },
  { "id": 102, "title": "後端開發", "company": "騰訊" }
]

// GET /api/job/detail/101
{
  "id": 101,
  "title": "前端開發",
  "description": "負責前端頁面開發",
  "company": "阿里巴巴"
}

子應用:找企業(child-vue3-job)

功能:

  • 企業列表 /api/company/list GET
  • 企業詳情 /api/company/detail/:id GET

mock 示例:

// GET /api/company/list
[
  { "id": 201, "name": "字節跳動", "industry": "互聯網" },
  { "id": 202, "name": "百度", "industry": "AI" }
]

// GET /api/company/detail/201
{
  "id": 201,
  "name": "字節跳動",
  "industry": "互聯網",
  "location": "北京"
}

子應用:關於我們(child-react18-about)

功能:

  • 關於我們 /api/about/info GET

mock 示例:

// GET /api/about/info
{
  "company": "微前端平台",
  "description": "一個多技術棧集成的企業級系統"
}
  1. Mock Server 工具推薦:
  2. 使用 Mock Service Worker (MSW)(適用於 Vue/React/Nuxt 等)
  3. 或者本地 node server + json-server/mockjs
  4. 接口統一管理:
  5. 每個子應用維護自己的接口配置
  6. 主應用統一配置公共接口(如認證相關)
  7. 前後端聯調方式:
  8. 使用 axios 攔截器統一處理 token
  9. 子應用通過環境變量控制是否啓用 mock

實現基座應用

目前使用 node(v18.20.6)

pnpm create vue@latest
# ts
# pina
# vue-router
cd micro-main-vue3
pnpm install
pnpm dev
# 安裝相關依賴 router
# /router目錄下放置路由
# /views目錄下放視圖
# /views/child目錄下放子應用路由
# /views/main目錄下放基座應用的視圖
# 安裝element plus
  1. 基座應用上集成 microapp
@micro-zoe/micro-app
  1. 項目的 main.js 中引入它並且初始它,具體實現看去 github 上看
import microApp from '@micro-zoe/micro-app';

microApp.start();

使用 nust2 實現首頁應用(child-nuxt3-home)

它是基於 vue3 的服務端渲染項目(我學習的版本使用的是 vue3 我用的也是 nuxt3)

pnpm create nuxt-app child-nuxt3-home

功能開發完成後,集成到基座應用中,使用<micro-app name="child-app" url="http://localhost:3000/child-home"></micro-app>, 但它會提示跨域問題,我們可以在 chrome 中添加了一個插件來測試允許跨域,插件名:Allow CORS: Access-Control-Allow-Origin

使用 vue2 構建一個子應用找工作(micro-child-vue2-job)

micro-child-vue2-job/
├── public/
│ └── index.html
├── src/
│ ├── assets/
│ ├── components/
│ ├── views/
│ ├── App.vue
│ ├── main.js
│ └── router.js
├── .gitignore
├── babel.config.js
├── package.json
└── README.md

vue3 構建一個子應用找企業(micro-child-vue3-enterprise)

2024-04-12

接口 mock 調整及列表數據展示

功能改動

  1. 添加接口代理配置
  2. 新增 .env.development 文件配置環境變量
  3. vue.config.js 中添加代理配置,支持接口轉發
  4. 配置 mock 接口地址:http://127.0.0.1:4523/m1/6202454-5895755-default
  5. 調整職位列表樣式
  6. 移除列表容器背景色
  7. 優化職位卡片樣式
  8. 調整字體大小和顏色
  9. 添加卡片懸停效果
  10. 優化標籤樣式
  11. 完善列表數據展示
  12. 展示職位基本信息(標題、薪資)
  13. 展示公司信息(Logo、名稱、行業)
  14. 展示職位標籤(地點、經驗、學歷)
  15. 展示福利標籤
  16. 展示技能標籤
  17. 添加分頁功能

文件變更

  • 新增文件:
  • .env.development:環境配置文件
  • 修改文件:
  • src/api/findJobApi.js:添加接口調試日誌
  • src/assets/scss/findjob.scss:調整樣式
  • src/utils/request.js:調整請求配置
  • src/views/FindJob.vue:完善列表展示
  • vue.config.js:添加代理配置

接口數據結構

{
  "code": 200,
  "message": "success",
  "data": {
    "list": [
      {
        "jobId": "job-100",
        "jobTitle": "產品經理",
        "enterpriseName": "騰訊科技",
        "enterpriseLogo": "https://logo.clearbit.com/mi.com",
        "industry": "人工智能",
        "jobType": "全職",
        "education": "本科",
        "workCity": "北京市",
        "workExperience": "1年",
        "salaryMin": 10642,
        "salaryMax": 17846,
        "salaryRange": "10642-17846元/月",
        "salaryUnit": "月",
        "welfareTags": ["五險一金", "交通補貼", "加班補助"],
        "skillTags": ["Python", "TensorFlow", "PyTorch"],
        "refreshTimeStr": "2024年4月12日"
      }
    ],
    "total": 25
  }
}

樣式規範

  • 主色調:#4e6ef2
  • 標題文字:16px, #333
  • 薪資文字:16px, #ff6b6b
  • 普通文字:13px, #666
  • 次要文字:12px, #999
  • 標籤樣式:
  • 背景色:#f8f9fc
  • 文字顏色:#666
  • 圓角:2px
  • 卡片樣式:
  • 背景色:#fff
  • 內邊距:24px
  • 圓角:4px
  • 陰影:0 1px 3px rgba(0, 0, 0, 0.02)

創建 react 應用

 npx create-react-app micro-child-react18-about

基於 React 18 的微前端子應用,支持獨立運行和作為子應用運行。

項目結構

micro-child-react18-about/
├── public/                 # 靜態資源目錄
├── src/                    # 源代碼目錄
│   ├── components/         # 公共組件
│   │   └── Layout/        # 佈局組件
│   ├── pages/             # 頁面組件
│   │   └── About/         # 關於頁面
│   ├── styles/            # 樣式文件
│   │   └── global.scss    # 全局樣式
│   ├── utils/             # 工具函數
│   │   └── request.js     # 請求封裝
│   ├── App.js             # 應用入口組件
│   ├── index.js           # 應用入口文件
│   └── public-path.js     # 微前端環境配置
├── .env                    # 環境變量
├── package.json           # 項目依賴配置
└── README.md              # 項目說明文檔

micro 沙箱體(js 隔離)

  1. new Fuction("return window")()
  2. (0,eval)("window")
  3. window.rawWindow

比如職位類型可能幾個子應該都用到職位類型,我們可以將其提取到基座應該中,另外我們可以在子應用中通過window.__MICRO_APP_PUBLIC_PATH__
如果在主應用中顯示 micro-app 不能識別的警告,但不影響使用我們需要在主應用中添加一些配置,在基座應用中 vite.config.js 中添加

//...
plugins: [
  vue({
    template: {
      compilerOptions: {
        isCustomElement: (tag) => /^micro-app/.test(tag),
      },
    },
  }),
];
// ..

使用基座應用數據的邏輯

mounted() {
  if (window.__MICRO_APP_ENVIRONMENT__) {
    // 微前端環境
    this.jobTypeArr = window.rawWindow.jobTypeArr;
  } else {
    this.jobTypeArr = jobTypeArr;
  }
  // this.getAddressDict();
  // this.searchJobList();
}

樣式隔離(默認開啓)

通過基座應該設置前綴來隔離,通過命名空間來

<el-config-provider namespace="ep">
  <common-header v-if="route.name !== 'login'" />
  <main-container />
  <common-footer v-if="route.name !== 'login'" />
</el-config-provider>

創建一個 scss 文件將

// styles/element/index.scss
// we can add this to custom namespace, default is 'el'
@forward 'element-plus/theme-chalk/src/mixins/config.scss' with (
  $namespace: 'ep'
);
// ...

注釋掉 main 中的引入import 'element-plus/dist/index.css' 換成 scss 文件

在 vite.config 配置中聲明

css: {
  preprocessorOptions: {
    scss: {
      additionalData: `@use "./src/styles/element/index.scss" as *;`,
    },
  },
},

元 s 隔離

shadow dom 元素可以重復,但又不會產生衝突,所有元素都不會逃離micro-app這個邊界

生命週期(micro-app)

可以 start 上配置lifeCycles,也可以在每一個標準上使用@mounted來為每一個子應該設置

主子通信

micro-app標籤上添加數據

import microApp from '@micro-zoe/micro-app'
const globalData = microApp.getGlobalData()
<micro-app :data="globalData"></micro-app>

在子應用項目中

if (window.__MICRO_APP_ENVIROMENT__) {
  const dataForchild = window.microApp.getData();
  // 獲取數據對象
  const { token } = dataForChild;
  axios.defaults.headers['x-client-token'] = token;
}

也可以使用microApp.setData('childEnterprise',data) 來設置,這個名字要和micro-app的 name 保持一致

子應用向主應用發送數據

if (window.__MICRO_APP_ENVIRONMENT__) {
  window.microApp.dispatch({
    activeIndex: 'job',
  });
}
// 在基座應用中獲取數據
<script setup>
function handleDataChange(e) {
  let { activeIndex } = e.detail.data;
  localStorage.setItem('activeIndex', activeIndex);
}
</script>

<template>
  <div>
    <micro-app
      @datachange="handleDataChange"
      name="childHome"
      url="http://localhost:3000/childHome/"
    ></micro-app>
  </div>
</template>

<style></style>

子應用間通信

在首頁應用點擊搜索,把關鍵字帶入到找工作子應用

  1. 判斷是不是微前端環境
  2. 把數據發給基座
searchIt() {
  let { homeSearchValue } = this;
  if (window.__MICRO_APP_ENVIRONMENT__) {
    window.microApp.setGlobalData({ homeSearchValue });
    const baseRouter = window.microApp.router.getBaseAppRouter();
    baseRouter.push('/main/childJob');
  }
},
// 應用啓動時要註冊其路由信息
microApp.router.setBaseAppRouter(router) //router是基座路由信息
// 在找工作子應用的mounted中把數據拿出來添加到查詢接口的參數中
const globalData = window.microApp.getGlobalData()
if(globalData){

}

主應用跳轉子應用,我們在基座應用的路由中已經處理過了,如何從子應用跳轉到主應用(刷新頁面跳,不刷新頁面跳)

// 1.
window.microApp.location.href = '/main/login';
// 2
// 獲取基座應用的路由然後來設置
const baseRouter = window.microApp.router.getBaseAppRouter();
baseRouter.push('/main/login');

微前端應用的優化

預加載:requestIdleCallback 在瀏覽器不忙的時候把資源加載一下,在基座應用中在 start({})對象中添加屬性prefetchApps

import microApp from '@micro-zoe/micro-app';

microApp.start({
  prefetchApps: [
    {
      name: 'childHome',
      url: 'http://localhost:3000/childHome/',
      level: 3,
    },
    {
      name: 'childJob',
      url: 'http://localhost:8080',
      level: 3,
    },
    {
      name: 'childEnterprise',
      url: 'http://localhost:3002/child/findEnterprise/',
      level: 3,
      iframe: true,
    },
    {
      name: 'childAbout',
      url: 'http://localhost:3003/',
      level: 3,
    },
  ],
});

要和標籤的配置保持一致

配前端的資源共享,加載一次,其它子應用加載時從緩存中獲取

globalAssets 項配置,但這個配置不是很好,可以在 index.html 中給 link 標籤和 script 標籤添加 global 屬性來標識

<link global rel="stylesheet" href="xx.css" />
<script global src="xx.js"></script>

子應用緩存,keep-alive 不會真正的被卸載,加載的生命週期是 afterHide beforeShow afterShow

絲滑轉場

頁面加載動效(或者骨架屏),基座應用加載完之後它消失,注意幾個點 基座應用加載完成前端的 loading, micro-app 加載前後的 loading,及子應用渲染完成前後,還有點是每個子應用的獨立個體的性能優化

優雅上線

這個已經不是我的學習重點了,過一下得了。如需要瞭解移步其它課程的學習

每一個應用單獨打包部署,且集成到基座應用中,生部署子系統應用,然後再部署基座應用

發佈工具

  • Putty
  • Xftp

服務器環境依賴

  • Nodejs 16.11.0
  • Nginx
  • Screen

線上域名

  • localhost
  • 線上域名
  • 📘 統一管理本地和線上 url

發佈線上

🚩 子應用部署

  • Nuxt2 子應用
  • Vue2 子應用
  • Vue3 子應用
  • React18 子應用
  • Gzip 壓縮

🟡 基座應用部署

  • Vue3 主應用

多頁應用

mpa 不同與我們的微前端架構(單一技術架構),不能為了技術而技術,vue2 實現一個多頁面應用(也不是這個的重點)

主題測試文章,只做測試使用。發佈者:Walker,轉轉請注明出處:https://walker-learn.xyz/archives/4451

(0)
Walker的頭像Walker
上一篇 2026年3月10日 00:00
下一篇 2026年3月8日 15:40

相關推薦

  • Go工程師體系課 012【學習筆記】

    Go 中集成 Elasticsearch 1. 客戶端庫選擇 1.1 主流 Go ES 客戶端 olivere/elastic:功能最全面,API 設計優雅,支持 ES 7.x/8.x elastic/go-elasticsearch:官方客戶端,輕量級,更接近原生 REST API go-elasticsearch/elasticsearch:社區維護的官…

    個人 2025年11月25日
    28000
  • Node深入淺出(聖思園教育) 003【學習筆記】

    WebSocket 與 SSE 總覽 WebSocket 基礎 定位:WebSocket 是一條在 HTTP 握手後升級的全雙工連接,允許客戶端與服務器在同一 TCP 通道上雙向推送數據,省去了反復輪詢。 握手流程: 客戶端通過 Upgrade: websocket 頭髮起 HTTP 請求; 服務器響應 101 Switching Protocols,雙方協…

    個人 2025年11月24日
    39600
  • Go工程師體系課 006【學習筆記】

    項目結構說明:user-web 模塊 user-web 是 joyshop_api 工程中的用戶服務 Web 層模塊,負責處理用戶相關的 HTTP 請求、參數校驗、業務路由以及調用後端接口等功能。以下是目錄結構說明: user-web/ ├── api/ # 控制器層,定義業務接口處理邏輯 ├── config/ # 配置模塊,包含系統配置結構體及讀取邏輯 …

    個人 2025年11月25日
    28500
  • 熱愛運動,挑戰極限,擁抱自然

    熱愛 在這個快節奏的時代,我們被工作、生活的壓力所包圍,常常忽略了身體的需求。而運動,不僅僅是一種健身方式,更是一種釋放自我、挑戰極限、與自然共舞的生活態度。無論是滑雪、攀岩、衝浪,還是跑步、騎行、瑜伽,每一種運動都能讓我們找到內心的激情,感受到生命的躍動。 運動是一場自我挑戰 挑戰極限,不僅僅是職業運動員的專屬,而是每一個熱愛運動的人都可以追求的目標。它可…

    個人 2025年2月26日
    1.4K00
  • Node深入淺出(聖思園教育) 002【學習筆記】

    node 的包管理機制和加載機制 npm search xxxnpm view xxxnpm install xxx nodejs 文件系統操作的 api Node.js 的 fs 模塊提供同步(Sync)與基於回調/Promise 的異步 API,可以操作本地文件與目錄。日常開發中常用的能力包括讀取、寫入、追加、刪除、遍歷目錄、監聽變化等。以下示例基於 C…

    個人 2025年11月24日
    30100
簡體中文 繁體中文 English