微前端架构学习笔记
前言
之前遇到过一个需求,有两个项目分别由两个不同的部门负责,不同技术栈,不同代码仓库:
- A 项目是官网,负责展示产品亮点等信息,有多个入口可以进入 B 项目中的不同页面。
- B 项目是业务线,负责处理具体的功能,可以跳转到 A 项目中登录/注册等。
现在想在这样跨域的两个项目之间,仅通过两个客户端,如何传递客户从 A 项目中上传的文件,使得 B 项目可以接收文件再处理后续的业务逻辑。
因为并未引入微前端方案,最终通过 传递文件的 DataURL + IndexedDB 的方式来实现。
跑题一点,每个文件都可以生成 DataURL 和 BlobURL,在这篇文章中不展开讲了,之后会更新一篇文章记录两者的使用。
最终决定使用 DataURL 的原因是,涉及到链接跳转的动作,会导致 BlobURL 丢失。
如果引入了微前端的方案,那么这个问题就很好解决,下面将详细记录微前端相关的笔记。
1.什么是微前端?
微前端(Micro Frontends)是一种将前端应用程序拆分成多个较小、独立、可管理的部分的架构方法。

图片来源于micro-app官网
微前端借鉴微服务架构(Micro Services),将一个前端应用程序拆分成多个子应用,子应用可以分别独立开发、测试、部署和维护。
微前端平台
single-spa
将多个独立的单页面应用组合到一个父应用中的微前端框架
特点
- 无框架限制
对于 React,可以使用 single-spa-react
对于 Vue,可以使用 single-spa-vue
对于 Angular,可以使用 single-spa-angular
- 可以与其他微前端框架(如 qiankun)结合使用
- 主应用与子应用无耦合,每个子应用都可以独立加载和卸载
缺点
- 配置较为繁琐,需要开发者手动管理每个子应用的生命周期和加载
要求子应用暴露三个生命周期方法(
bootstrap、mount、unmount),并且需要对子应用的入口进行适当的修改。适用场景
- 需要多种前端技术栈共存的项目
- 可以与现有的应用逐步迁移到微前端架构中
以 Vue3.0 为例,借用 single-spa-vue
npm install vue@next single-spa-vue目录结构
my-micro-frontend/ ├── dist/ # 构建后的输出 ├── public/ │ └── index.html # 主页面,包含单页面应用入口 ├── src/ │ ├── main.ts # 主应用,加载子应用 │ ├── vue-app.ts # 子应用生命周期方法 │ ├── vue-app.vue # Vue 3 组件 ├── tsconfig.json # TypeScript 配置 ├── webpack.config.js (or vite.config.ts) └── package.json配置子应用
// vue-app.vue <template><div id="app"><h1>Vue 3 Micro Frontend</h1><p>This is a micro frontend app rendered using Vue 3 and Single-spa!</p></div> </template><script setup lang="ts"> /*** 这个组件通过 single-spa 在主应用中渲染*/ </script>在
vue-app.ts中,使用 singleSpaVue 暴露bootstrap、mount和unmount方法。// vue-app.ts import { createApp, App as VueApp } from "vue"; import { singleSpaVue } from "single-spa-vue"; import App from "./App.vue";// 定义 Single-spa 生命周期方法的类型 const vueLifecycles = singleSpaVue({createApp,appOptions: {render: (h: any) => h(App), // 渲染根组件}, });// 暴露 Single-spa 所需的生命周期方法 export const bootstrap: (props: any) => Promise<void> = vueLifecycles.bootstrap; export const mount: (props: any) => Promise<void> = vueLifecycles.mount; export const unmount: (props: any) => Promise<void> = vueLifecycles.unmount;配置主应用
主应用负责注册子应用并启动
single-spa,不需要直接渲染 Vue 应用。在主应用中不需要手动调用createApp(App).mount('#app'),都由single-spa-vue管理。// main.ts import { registerApplication, start } from "single-spa";// 注册 Vue 子应用 registerApplication("vue-app", // 子应用名称() => import("./vue-app.ts"), // 动态导入子应用生命周期方法(location) => location.pathname.startsWith("/vue-app") // 激活条件 );// 启动 single-spa start();配置 Webpack 或 Vite
// webpack.config.js const path = require("path");module.exports = {entry: "./src/main.ts",output: {path: path.resolve(__dirname, "dist"),filename: "bundle.js",publicPath: "/",},resolve: {extensions: [".ts", ".js", ".vue", ".json"],alias: {vue: "vue/dist/vue.esm-bundler.js",},},module: {rules: [{test: /\.ts$/,loader: "ts-loader",exclude: /node_modules/,},{test: /\.vue$/,loader: "vue-loader",},],},plugins: [new (require("vue-loader").VueLoaderPlugin)(),],devServer: {historyApiFallback: true,}, };// vite.config.ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue";export default defineConfig({plugins: [vue()],build: {target: "esnext",outDir: "dist",lib: {entry: "src/vue-app.ts",name: "VueApp",fileName: "vue-app",formats: ["es"],},rollupOptions: {external: ["vue"],},}, });qiankun
基于 single-spa 的微前端实现库,提供了更易用的 API
特点
- 无框架限制
- 支持按需加载子应用,支持懒加载、动态加载
- 提供沙箱机制,可以隔离不同微前端应用的全局状态
- 支持使用插件系统来扩展功能
缺点
- 封装了 single-spa,因此继承了对子应用的生命周期管理
适用场景
- 适合已有单页面应用架构,并计划迁移或拆分成多个微前端应用的场景
MicroApp
基于 WebComponent 的微前端框架,使用原生浏览器支持的 Web Component 标准来封装和管理微前端应用
特点
- 将每个微前端应用封装为 Web Component,子应用能够更好地与其他应用隔离
- Web Component 是原生浏览器技术,MicroApp 不依赖任何前端框架
- 支持自定义生命周期函数,能精细控制子应用的加载、渲染、销毁等过程
缺点
- Web Component 在不同浏览器的兼容性可能会存在差异
- 对开发者来说,需要一定的 Web Component 知识
适用场景
- 适合希望轻量化的微前端架构,或者不希望依赖第三方框架的场景
- 对应用的封装性和隔离性有较高要求的场景
Module federation
Webpack 5 引入的一个新特性,允许将一个应用的模块动态加载到另一个应用中。
特点
- 能够共享模块,比如 React 和 Vue 等常用依赖,避免重复加载
- 可以按需加载子应用,并支持运行时动态决定要加载哪些模块
- 不依赖框架,是直接基于 Webpack 的构建系统
缺点
- 配置复杂,需要对 Webpack 的运行机制有较深入的了解
- 很少提供封装好的 API,开发者需要更多的手动管理
适用场景
- 适合已经使用 Webpack 的项目,特别是对微前端的集成要求较高的场景
2.微前端的架构实现方式
1)基于 URL 路由
通过 URL 路由来加载不同的微前端子应用
假设有一个电商平台,主应用是一个统一的首页展示,而不同的页面(如产品详情页、用户中心、购物车等)分别由不同的子应用负责。
- 使用主应用中的路由管理器来控制子应用的加载和渲染。
- 主应用的路由会根据 URL 地址来决定展示哪个子应用的页面。
// 主应用路由配置示例
const routes = [{ path: '/products', component: ProductApp },{ path: '/cart', component: CartApp },{ path: '/user', component: UserApp }
];
2)基于 Web Components
使用 Web Components 技术来将不同的子应用封装成独立的组件。这样可以确保每个子应用的样式和功能相互隔离,避免冲突。
假设有一个新闻网站,主应用展示统一的导航栏和布局,而每个新闻分类(如国内新闻、国际新闻、科技新闻)由不同的微前端子应用负责。
- 每个子应用作为一个独立的 Web Component 封装,主应用直接通过
<my-product-app></my-product-app>这样的标签来加载和渲染。 - Web Components 提供了封装功能,避免了样式和脚本冲突。
基础写法
// 子应用:ProductApp 使用 Web Components 封装
class ProductApp extends HTMLElement {connectedCallback() {this.innerHTML = `<div>Product List</div>`;}
}customElements.define('my-product-app', ProductApp);// 主应用直接使用 Web Component
<my-product-app></my-product-app>
复杂结构写法
// 定义子应用组件 ProductApp
class ProductApp extends HTMLElement {constructor() {super();this.attachShadow({ mode: 'open' }); // 使用 Shadow DOM,避免样式污染}connectedCallback() {this.render();}render() {const template = document.createElement('template');template.innerHTML = `<style>.product-list {color: #333;font-size: 16px;}.product-item {margin: 10px 0;}</style><div class="product-list"><div class="product-item">Product 1</div><div class="product-item">Product 2</div><div class="product-item">Product 3</div></div>`;// 将模板内容插入 Shadow DOMthis.shadowRoot.appendChild(template.content.cloneNode(true));}
}// 注册自定义元素
customElements.define('my-product-app', ProductApp);
// 在主应用中
<my-product-app></my-product-app>
通过 Shadow DOM 进行样式隔离,也可以使用外部样式表。Shadow DOM 有两个主要好处:
- 样式封装:子应用的样式不会影响到主应用或其他子应用。
- DOM 隔离:确保子应用的内部结构和样式不会被外部应用干扰。
使用外部样式表
class ProductApp extends HTMLElement {constructor() {super();this.attachShadow({ mode: 'open' });}connectedCallback() {this.render();}render() {// 引入外部样式const link = document.createElement('link');link.rel = 'stylesheet';link.href = 'styles.css'; // 外部 CSS 文件// 模板内容const template = document.createElement('template');template.innerHTML = `<div class="product-list"><div class="product-item">Product 1</div><div class="product-item">Product 2</div><div class="product-item">Product 3</div></div>`;// 将样式和模板添加到 Shadow DOMthis.shadowRoot.appendChild(link);this.shadowRoot.appendChild(template.content.cloneNode(true));}
}
3)基于 JavaScript 动态加载
使用 JavaScript 动态加载工具(如 Webpack)来按需加载不同的子应用。
假设有一个在线教育平台,主应用加载时并不加载所有课程内容,而是按需加载不同课程模块。
- 在主应用中通过
import()动态加载子应用的 JavaScript 模块。
// 使用 Webpack 动态加载子应用
const loadCourseApp = () => {import(/* webpackChunkName: "course-app" */ './course-app').then(module => {module.renderCoursePage();}).catch(err => {console.error('Error loading course app:', err);});
};
4)基于 iFrame
每个子应用运行在一个独立的 iFrame 中,彼此之间无任何依赖。
假设有一个跨域的企业管理平台,不同的部门使用不同的子系统(如人事管理、财务管理等),每个部门的系统是独立的。
- 每个子应用运行在独立的 iFrame 中,iFrame 嵌入到主应用页面中。
- 可以完全隔离不同的子系统,避免了跨域和样式冲突的问题。
<!-- 主应用使用 iFrame 嵌入子应用 -->
<iframe src="https://example.com/finance" width="100%" height="500px"></iframe>
<iframe src="https://example.com/hr" width="100%" height="500px"></iframe>
3.类单页应用
4.参考文章链接
https://tech.meituan.com/tags/%E5%BE%AE%E5%89%8D%E7%AB%AF.html
https://wujie-micro.github.io/doc/guide/
https://juejin.cn/post/7113503219904430111
https://developer.jdcloud.com/article/2898
相关文章:
微前端架构学习笔记
前言 之前遇到过一个需求,有两个项目分别由两个不同的部门负责,不同技术栈,不同代码仓库: A 项目是官网,负责展示产品亮点等信息,有多个入口可以进入 B 项目中的不同页面。B 项目是业务线,负责…...
DApp开发:从合约到系统快速上线解决方案
在区块链技术迅猛发展的今天,去中心化应用(DApp)作为区块链的一项重要应用,已经吸引了众多开发者和企业的关注。与传统应用程序不同,DApp依托于区块链的去中心化特点,实现了透明、安全、不可篡改等优势&…...
react 中 useState 中的 set 方法异步解决
使用 useEffect 监听状态的改变。 一、异步特性 在批量处理状态更新时,用以提高性能。 二、异步解决 使用useEffect来处理更新后的状态,useEffect钩子在组件渲染后执行,并且会在依赖项(第二个参数)发生变化时重新执…...
UAC2.0 speaker——带反馈端点的 USB speaker(16bit 单声道)
UAC2.0 speaker 系列文章 UAC2.0 speaker——单声道 USB speaker(16bit) UAC2.0 speaker——类特殊请求 UAC2.0 speaker——音量控制 UAC2.0 speaker——多采样率支持 UAC2.0 speaker——24/32bit 支持 UAC2.0 speaker——speaker 数据传输 UAC2.0 speaker——同时支持 16bi…...
docker的简单使用
文章目录 docker简介docker架构镜像和容器镜像有关的常用命令容器相关常用命令 docker简介 Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。 Docker可以让开方子打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到…...
Selenium:强大的 Web 自动化测试工具
Selenium:强大的 Web 自动化测试工具 在当今的软件开发和测试领域,自动化工具的重要性日益凸显。Selenium 就是一款备受欢迎的 Web 自动化测试工具,它为开发者和测试人员提供了强大的功能和便利。本文将详细介绍 Selenium 是什么,…...
设计模式 在PLM系统的应用场景介绍
通义灵码 设计模式在 PLM(产品生命周期管理)系统中扮演着重要的角色,可以帮助开发人员更好地组织代码、提高系统的可维护性和扩展性。以下是一些常见的设计模式及其在 PLM 系统中的应用场景: 1. 单例模式(Singleton …...
C#请求https提示未能为 SSL/TLS 安全通道建立信任关系
System.Net.WebException: 基础连接已经关闭: 未能为 SSL/TLS 安全通道建立信任关系 ,这个错误通常表明你的应用程序在尝试建立一个安全的 SSL/TLS 连接时遇到了问题。这通常是由于证书验证失败引起的。证书验证失败可能有几个原因: 证书不受信任&#…...
【人工智能】GaussDB数据库技术及应用
文章目录 前言一、数据库的基本概念及发展演进1、数据库概念DB2、数据库管理系统概念DBMS3、数据库与数据库管理系统的关系4、数据库的演进及发展5、数据模型的基本概念6、数据模型的要求和类型7、层次模型的基本概念8、网状模型的基本概念8、关系模型的基本概念9、非关系模型的…...
OpenAI12天 –第3天的实时更新,包括 ChatGPT、Sora、o1 等
OpenAI提前开启了假期,推出了为期 12 天的活动,名为“OpenAI 12 天”。在接下来的一周左右的每一天,OpenAI 都将发布现有产品的新更新以及新软件,包括备受期待的 Sora AI 视频生成器。 OpenAI 首席执行官 Sam Altman 表示&#x…...
删除Yocto中build-x9hp_ms_a12_vemmc_ap2/tmp/work/aarch64-sdrv-linux/package后再编译出错问题
前言: 在yocto编译中,一般会添加自己的package并编译打包到yocto里去。这个包里的内容有时候需要添加或者删除。但是我删除了文件,在编译完成烧录到板子上,里面还有自己删除的文件,于是就在yocto搜索哪个目录有该文件&…...
2024三掌柜赠书活动第三十五期:Redis 应用实例
目录 前言 Redis操作都会,却不知道怎么用? 关于《Redis 应用实例》 编辑推荐 内容简介 作者简介 图书目录 《Redis 应用实例》全书速览 拓展:Redis使用场景 实例1:缓存应用 场景描述 实现方法 具体代码示例 实例2&a…...
观察者模式的理解和实践
引言 在软件开发中,设计模式是开发者们为了解决常见的设计问题而总结出来的一系列最佳实践。观察者模式(Observer Pattern)是其中一种非常经典且使用率极高的设计模式。它主要用于定义对象之间的一对多关系,使得当一个对象的状态发…...
查看Windows系统上的Redis服务器是否设置了密码
查看 Redis 配置文件 1.找到 Redis 配置文件: 通常Redis配置文件名为 redis.windows.conf 或 redis.conf,它位于Redis安装目录中。 2.打开配置文件: 使用文本编辑器(如Notepad、VS Code等)打开该文件。 3.查找 re…...
认识Java中的异常(半成品)
1.异常的概念与体系结构 1.1在Java中,将程序执行过程中发生的不正常行为称为异常.比如 1.算数异常 public class Main1 {public static void main(String[] args){System.out.println(10/0);} } //异常信息为:Exception in thread "main" java.lang.ArithmeticExc…...
生成SSH秘钥文件
git生成文件命令 # 配置用户名和邮箱 git config --global user.name "你的GitHub用户名" git config --global user.email "你的GitHub邮箱"# 生成ssh-key ssh-keygen -t rsa -C “你的GitHub邮箱" # 验证 ssh -T gitgithub .com 第一步:…...
wsl2子系统ubuntu发行版位置迁移步骤
默认的wsl2发行版是安装在windos的c盘,占用空间较大,有迁移需求,也可以迁移到其他电脑; 查看现有发行版信息 运行以下命令查看现有的 WSL 发行版及其状态: wsl --list --verbose# 输出示例NAME STATE …...
协程设计原理与实现
协程设计原理与汇编实现 同步与异步 对于任何一个事情,都可以划分为不同的步骤。所谓同步,就先做第一个事情,按照这件事的步骤完成这件事之后,再去做第二件事。再去做第三件事,以此类推。 异步就是,可以…...
合并区间C和C++的区别、布尔、整型、浮点、指针类型和0做比较、malloc、calloc、realloc的区别
56. 合并区间 class Solution { public:vector<vector<int>> merge(vector<vector<int>>& intervals) {//先按照每个区间的左元素排序,这样每个区间的左边界就固定了,所以之后考虑相邻的//区间是否是相交的就行 类似与栈的…...
Flutter 图片编辑板(一) 事件路由
一个图片编辑板,有两部分组成。编辑板和内容项。每一个内容项是被InteractiveViewer修饰的widget,具有缩放偏移的功能。 在图片编辑板上, 会有多个内容相,图片或文字(添加文字目前还没做过)。 当要编辑其中…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...
