欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

微前端学习

最编程 2024-07-10 14:11:12
...

概念

首先我们要明确一个问题,微前端到底是什么。微前端源自于微服务,而微服务的概念出现是为了处理庞大的后端结构的臃肿问题。微前端是处理前端项目的臃肿问题,

特点

将庞大的整体拆成可控的小块,并明确它们之间的依赖关系。关键优势在于:

代码库更小,更内聚、可维护性更高

松耦合、自治的团队可扩展性更好

代码的迭代更加简单,甚至可以重写部分功能很少甚至不会对彼此造成影响。

为什么之前的代码难改,‘祖传’代码多,关系复杂,牵一发而动全身。技术栈落后,但是引用太多,配置太多不敢改。改以部分功能,难度不亚于重写。

而微前端不一样,可以独立部署。 A A , B 是 B ,彼此不会影响,大家只能算是邻居,家庭内部矛盾,自己解决,关上门解决问题。打开门一起 Happy 。开发人员和项目代码全都是独立的,甚至可以请不同的团队开发不同的代码。谁好了谁先上,节约成本。

实现方案

多 Bundle 集成

    微前端架构中一般会有个容器应用(container application)将各子应用集成起来,职责如下:

    渲染公共的页面元素,比如 header、footer

    解决横切关注点(cross-cutting concerns),如身份验证和导航

    将各个微前端整合到一个页面上,并控制微前端的渲染区域和时机

    集成方式分为 3 类:

        服务端集成:如 SSR 拼装模板

        构建时集成:如 Code Splitting

        运行时集成:如通过 iframe、JS、Web Components 等方式

构建时集成

常见的构建时集成方式是将子应用发布成独立的 npm 包,共同作为主应用的依赖项,构建生成一个供部署的 JS Bundle

然而,构建时集成最大的问题是会在发布阶段造成耦合,任何一个子应用有变更,都要整个重新编译,意味着对于产品局部的小改动也要发布一个新版本,因此,不推荐这种方式

运行时集成

将集成时机从构建时推迟到运行时,就能避免发布阶段的耦合。常见的运行时集成方式有:

    iframe

    JS:比如前端路由

    Web Components

虽然直觉上用 iframe 好像不太好(性能、通信成本等),但在这里确实是个合理选项,因为 iframe 无疑是最简单的方式,还天然支持样式隔离以及全局变量隔离

但这种原生的隔离性,意味着很难把应用的各个部分联系到一起,路由控制、历史栈管理、深度链接(deep-linking)、响应式布局等都变得异常复杂,因而限制了 iframe 方案的灵活性

另一种最常见的方式是前端路由,每个子应用暴露出渲染函数,主应用在启动时加载各个子应用的独立 Bundle,之后根据路由规则渲染相应的子应用。目前看来,是最灵活的方式

还有一种类似的方式是Web Components,将每个子应用封装成自定义 HTML 元素(而不是前端路由方案中的渲染函数),以获得Shadow DOM带来的样式隔离等好处

影响隔离

子应用之间,以及子应用与主应用间的样式、作用域隔离是必须要考虑的问题,常见解决方案如下:

样式隔离:开发规范(如BEM)、CSS 预处理(如SASS)、模块定义(如CSS Module)、用 JS 来写(CSS-in-JS)、以及shadow DOM特性

作用域隔离:各种模块定义(如ES ModuleAMDCommon ModuleUMD

资源复用

资源复用对于 UI 一致性和代码复用有重要意义,但并非所有的可复用资源(如组件)都必须在一开始就提出来复用,建议的做法是前期允许一定程度的冗余,各个 Bundle 在各自的代码库中创建组件,直到形成相对明确的组件 API 时再建立可供复用的公共组件

另一方面,资源分为以下 3 类:

基础资源:完全不含逻辑功能的图标、标签、按钮等

UI 组件:含有一定 UI 逻辑的搜索框(如自动完成)、表格(如排序、筛选、分页)等

业务组件:含有业务逻辑

其中,不建议跨子应用复用业务组件,因为会造成高度耦合,增加变更成本

对于公共资源的归属和管理,一般有两种模式:

公共资源归属于所有人,即没有明确归属

公共资源归集中管理,由专人负责

从实践经验来看,前者很容易衍变成没有明确规范,且背离技术愿景的大杂烩,而后者会造成资源创建和使用的脱节,比较推荐的模式是开源软件的管理模式:所有人都能补充公共资源,但要有人(或一个团队)负责监管,以保证质量、一致性以及正确性

应用间通信

通过自定义事件间接通信是一种避免直接耦合的常用方式,此外,React 的单向数据流模型也能让依赖关系更加明确,对应到微前端中,从容器应用向子应用传递数据与回调函数

另外,路由参数除了能用于分享、书签等场景外,也可以作为一种通信手段,并且具有诸多优势:

其结构遵从定义明确的开放标准

页面级共享,能够全局访问

长度限制促使只传递必要的少量数据

面向用户的,有助于依照领域建模

声明式的,语义上更通用

迫使子应用之间间接通信,而不直接依赖对方

但原则上,无论采用哪种方式,都应该尽可能减少子应用间的通信,以避免大量弱依赖造成的强耦合

测试

每个子应用都应该有自己的全套测试方案,特殊之处在于,除单元测试、功能测试外,还要有集成测试:

集成测试:保证子应用间集成的正确性,比如跨子应用的交互操作

功能测试:保证页面组装的正确性

单元测试:保证底层业务逻辑和渲染逻辑的正确性

自下而上形成一个金字塔结构,每一层只需验证在其下层覆盖不到的部分即可

缺点

当然,这种架构模式并非百益而无一害,一些问题也随之而来:

导致依赖项冗余,增加用户的流量负担

团队自治程度的增加,可能会破坏协作


文档出处:https://zhuanlan.zhihu.com/p/96464401