从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工程师体系课 004【学习笔记】

    需求分析 后台管理系统 商品管理 商品列表 商品分类 品牌管理 品牌分类 订单管理 订单列表 用户信息管理 用户列表 用户地址 用户留言 轮播图管理 电商系统 登录页面 首页 商品搜索 商品分类导航 轮播图展示 推荐商品展示 商品详情页 商品图片展示 商品描述 商品规格选择 加入购物车 购物车 商品列表 数量调整 删除商品 结算功能 用户中心 订单中心 我的…

    2025年11月25日
    27700
  • Go工程师体系课 013【学习笔记】

    订单事务 先扣库存 后扣库存 都会对库存和订单都会有影响, 所以要使用分布式事务 业务(下单不对付)业务问题 支付成功再扣减(下单了,支付时没库存了) 订单扣减,不支付(订单超时归还)【常用方式】 事务和分布式事务 1. 什么是事务? 事务(Transaction)是数据库管理系统中的一个重要概念,它是一组数据库操作的集合,这些操作要么全部成功执行,要么全部…

    个人 2025年11月25日
    28800
  • 深入理解ES6 013【学习笔记】

    用模块封装代码 javascript用“共享一切”的方法加载代码,这是该语言中最容易出错且另人感到困惑的地方。其他语言使用诸如包这样的概念来定义代码作用域。在es6以前,在应用程序的每一个js中定义的一切都共享一个全局作用域。随着web应用程序变得更加复杂,js代码的使用量也开始增长,这一做法会引起问题,如命名冲突和安全问题。es6的一个目标是解决作用域问题…

    个人 2025年3月8日
    1.2K00
  • Go工程师体系课 protobuf_guide【学习笔记】

    Protocol Buffers 入门指南 1. 简介 Protocol Buffers(简称 protobuf)是 Google 开发的一种语言无关、平台无关、可扩展的结构化数据序列化机制。与 JSON、XML 等序列化方式相比,protobuf 更小、更快、更简单。 项目主页:https://github.com/protocolbuffers/prot…

    个人 2025年11月25日
    1.3K00
  • Nuxt3_扫盲 入门与原理介绍【学习笔记】

    Nuxt 3 入门与原理介绍 💡 什么是 Nuxt 3? Nuxt 3 是基于 Vue 3 和 Vite 打造的全栈前端框架,支持: 服务端渲染(SSR) 静态站点生成(SSG) 单页应用(SPA) 构建全栈应用(支持 API) Nuxt 3 是 Vue 的“加强版”,帮你简化项目结构和开发流程。 🔧 核心原理 功能 Nuxt 如何处理 ✅ 页面路由 自动根…

    个人 2025年4月6日
    2.2K00
简体中文 繁体中文 English