從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
上一篇 2025年4月6日 22:23
下一篇 2025年11月25日 17:00

相關推薦

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

    微服務開發 創建一個微服務項目,所有的項目微服務都在這個項目中進行,創建joyshop_srv,我們無創建用戶登錄註冊服務,所以我們在項目目錄下再創建一個目錄user_srv 及user_srv/global(全局的對象新建和初始化)user_srv/handler(業務邏輯代碼)user_srv/model(用戶相關的 model)user_srv/pro…

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

    node 從異步編程範式理解 Node.js Node.js 的定位與核心思想 基於 V8 引擎 + libuv 事件驅動庫,將 JavaScript 從瀏覽器帶到服務器側。 採用單線程事件循環處理 I/O,最大化利用 CPU 等待 I/O 的時間片,特別適合高併發、I/O 密集型場景。 “不要阻塞主線程”是設計哲學:盡量把耗時操作交給內核或線程池,回調結果…

    個人 2025年11月24日
    27700
  • 深入理解ES6 008【學習筆記】

    迭代器(Iterator)和生成器(Generator) 這個新特性對於高效的數據處理而言是不可或缺的,你也會發現在語言的其他特性中也都有迭代器的身影:新的for-of循環、展開運算符(...)、甚至連異步編程都可以使用迭代器。 迭代器是一種特殊的對象,它具有一些專門為迭代過程設計的專有接口,所有的迭代器對象都有一個next()方法,每次調用都返回一個結果對…

    個人 2025年3月8日
    1.1K00
  • Go工程師體系課 001【學習筆記】

    轉型 想在短時間系統轉到Go工程理由 提高CRUD,無自研框架經驗 拔高技術深度,做專、做精需求的同學 進階工程化,擁有良好開發規範和管理能力的 工程化的重要性 高級開的期望 良好的代碼規範 深入底層原理 熟悉架構 熟悉k8s的基礎架構 擴展知識廣度,知識的深度,規範的開發體系 四個大的階段 go語言基礎 微服務開發的(電商項目實戰) 自研微服務 自研然後重…

    個人 2025年11月25日
    27700
  • Go工程師體系課 protobuf_guide【學習筆記】

    Protocol Buffers 入門指南 1. 簡介 Protocol Buffers(簡稱 protobuf)是 Google 開發的一種語言無關、平台無關、可擴展的結構化數據序列化機制。與 JSON、XML 等序列化方式相比,protobuf 更小、更快、更簡單。 項目主頁:https://github.com/protocolbuffers/prot…

    個人 2025年11月25日
    1.2K00
簡體中文 繁體中文 English
歡迎🌹 Coding never stops, keep learning! 💡💻 光臨🌹