当前位置: 首页 > news >正文

【方案】网页由微应用拼图,微前端

大家好,欢迎来到停止重构的频道。

本期我们讨论:微前端

网站的前端网页是否可以像后端应用服务一样,可以拆分为独立开发的子应用,从而提升大型前端项目的协作效率与维护性呢。

我们按这样的顺序展开讨论

  1. 微前端及其好处
  2. iframe与单页应用的弊端
  3. 我们的解决方案
  4. 具体实现

微前端及其好处

微前端指的是一个大型前端应用拆分成多个小型前端应用,小型前端应用可独立开发、独立测试和独立部署。

以我们的官网为例,头部header和底部footer都是固定的,只有中间的部分是变化的。

我们对应的微前端解决方案为:打开的网页是一个基座网页,基座网页上有三个插槽,分别放入“头部Header”和“尾部Footer”。

当网页URL产生变化时,不会发生真正的网页跳转,而是由基座响应这个变化,只替换中间内容部分。

虽然这么说不太不准确,但是也可以这么理解

微前端,就是希望一个网页可以引入别的独立网页

被引入的独立网页可以独立开发、独立部署。

这么一说很多人会想到iframe,iframe确实是其中一个不太好的解决方案,后面会展开讨论。

这里需要补充说明的是,微前端与React/Vue等框架的组件概念是不一样的

微前端的网页碎片是夸工程且独立开发的,甚至一些微前端框架允许引入由不同技术栈开发的网页。

微前端的好处不言而喻,就是它能对需求变更、多团队合作等场景非常友好,所有的网页碎片都可以独立开发、独立替换

在网站特别复杂的时候,这种优势尤为明显,网站可划分更多的插槽,灵活嵌入更多的网页碎片 网页碎片中也可以挖多个插槽,嵌套插入网页碎片。

比如说,网站需要新增一个排行榜的小栏目,这个小栏目需要在多个网页中显示。

那么,微前端就可以单独开发一个排行榜网页,然后多个网页直接引入这个排行榜网页,并对其大小进行限制就可以了。

对于我们而言,我们希望一个大型网站是由多个子系统拼接而成的

其中,一个子系统的前端网页往往是一些碎片零件

比如博客系统的文章编写、文章展示这些网页零件,都不可能直接作为单独网页展示,而是需要嵌入到别的网页中作为其中一部分。

微前端的概念正好能解决这个问题。

也就是说,对于前端部分,我们可以直接接入已经开发好的子系统

而不是每次都从零开始,对着每次都大同小异的UI设计图,写着重复的代码。

这样对持续升级也是十分友好,不需要每次升级都对已有代码进行大范围修改。

iframe与单页应用的弊端

一听到,微前端就是,允许一个网页引入另一个网页

相信大家都会想到iframe,iframe允许在一个网页引入另一个网页,使用方便的同时隔离性也非常好。

虽然,网上有很多人说iframe性能差,基本的证据都是大同小异的。

就是网页是单线程,iframe与宿主网页共用线程会导致性能差。另外,就是iframe可能会加载重复的文件,导致性能浪费等等。

但是,iframe方案我坚持了很多个项目,它在使用上非常简单,不需要过多的学习成本。

另外,性能问题也是几乎是不存在的,毕竟用户并不是在用单片机上打开网页,iframe方案甚至比很多花里胡哨框架的响应速度还要高。

让我放弃iframe的理由是,iframe存在样式割裂的问题

比如弹出模块框,黑色背景不能全屏网站显示,若是想固定某个html元素,只能通过Js代码计算固定,而Js代码计算固定,会有抖动等不可解决的问题

对于微前端另一个比较常见的方案是单页应用

通过一个网页js入口,可以将网页碎片封装成各种组件,按需加载这些组件。

但是,这样是单个工程的解决方案,不能夸工程引入。

除非网站内容非常少,不然单论一个工程而言,团队合作中的代码冲突、目录混乱 都会让人头皮发麻。

当然,除了传统的单页应用工程,还有服务端渲染的框架,是可以允许夸工程引入的

但是,这些解决方案都有一个致命问题

就是在切换网页碎片时,浏览器虽然可以清理掉不再需要的HTML/CSS部分,但是却没办法清理不再需要的JS代码,也就是内存占用会越来越高

所以单页应用在大型网站的表现并不佳,把整个大型网站的前端做成一个单页应用也是不可行的,尝试过的团队,都是一做一个不吱声。

我们的解决方案

iframe和单页应用的弊端其实也凸显出了,微前端的两个核心问题

1、网页样式部分不希望有割裂感

2、JS部分需要可以清理

针对以上的核心问题,我们借鉴了wujie框架的设计思想。

将一个网页分成了两个部分:UI部分和Js部分。

UI部分放在宿主网页的ShadowDom中隔离,Js部分放在iframe沙箱中运行。

其中,ShadowDom是dom树下的隔离节点,与dom树在同一个文档流的同时,样式可以进行隔离。

这样就可以解决,纯Iframe方案,UI样式割裂的问题,也能解决,单页应用方案,JS代码累积的问题

Trick2也因此扩展了微前端相关功能,在开发调试网页时,按正常网页开发调试即可,当工程需要发布时,从原来的普通打包方式改为SPA方式即可

网页需要引入SPA方式打包的网页碎片时,需要采用_BoxPage组件引入

引入的方式也很简单,像iframe一样,就是设置目标网页的URL即可

具体实现

接下来是具体的实现方式,由于需要将网页分离为UI部分和Js部分UI部分放在ShadowDom中隔离,Js部分放在iframe沙箱中运行。

所以具体实现也分成了4个步骤,具体的代码实现可以翻看_BoxPage组件的源码。

  1. 分离网页的UI部分和JS部分
  2. 将UI部分插入宿主网页的ShadowDom中
  3. 将JS部分放入iframe沙箱中运行
  4. 重新关联UI部分和JS部分

首先是分离UI部分和JS部分,这部分其实很简单,就是将目标URL的HTML文本获取下来,再通过现成JS函数转换为HTML对象。

<link>标签和body为UI部分,<script>标签为JS部分。

分离完毕后,直接将UI部分写入当前网页的ShadowDom中,ShadowDom其实就是在HTML节点下开启一个ShadowDom节点,ShadowDom节点的窗体大小受外层节点的影响。

剩下的JS部分通过iframe的srcdoc属性写入即可,也就是iframe中只包含目标网页的JS部分。

值得一提的是,IOS的微信浏览器是不支持上述iframe属性的,需要通过比较老旧的方式写入。

最后一步是关联UI部分和JS部分,更具体的说,是劫持JS代码中的document、window等基础对象,使其指向Shadowdom中的UI部分。

这需要分两部分完成先是宿主网页需要创建proxy对象,用于替代JS代码中的document、window等基础对象。

创建proxy对象的原因,是可以精准控制哪些变量、函数使用宿主网页,哪些指向ShadowDom中的UI部分。

然后,在网页打包时需要将document、window对象改为宿主网页传入的proxy对象。

实际上就是在webpack打包时,将所有js文件的外层都套一层自动执行函数,就可以将document、window对象劫持为上面的proxy对象。

至于为什么我们源码中除了document、window对象以外,还劫持了其他对象

这些都是在调试时发现的,这些特殊对象的使用都存在于某些第三方库中,若不一并劫持,网页将运行不成功。

以上就是大概的实现步骤,具体可以翻看_BoxPage组件的代码,很多琐碎的细节没办法在这里展开。

总结

以上是我们的微前端解决方案。

我们希望微前端网页的引入方式跟iframe是一样的,只需要目标网页的URL。

微前端网页开发上也不希望有特殊适配,只需要更换打包方式即可。

我们的微前端方案,确实只是一个网页可以引入另一个独立网页。

与其他比较重的微前端解决方案不同,它们都包含更加复杂的网页跳转/切换方式,也就是网页路由。

关于网页路由,我们会在后续的网站基座解决方案提及,因为网页路由我们保持了最原始直接的a标签跳转。我们不希望徒增不必要的学习成本和多余的适配工作。

http://www.lryc.cn/news/596434.html

相关文章:

  • Node.js:RESPful API、多进程
  • 【STM32】CRC 校验函数
  • linux初识网络及UDP简单程序
  • 二、计算机网络技术——第3章:数据链路层
  • 基于卷积神经网络与小波变换的医学图像超分辨率算法复现
  • DeepSPV:一种从2D超声图像中估算3D脾脏体积的深度学习流程|文献速递-医学影像算法文献分享
  • zmaiFy来说软字幕和硬字幕有什么优缺点?
  • qtbase5-dev库使用介绍
  • 生成式人工智能对网络安全的影响
  • OpenCV快速入门之CV宝典
  • 博物馆智慧导览系统AR交互与自动感应技术:从虚实融合到智能讲解的技术实践
  • 内核协议栈源码阅读(一) ---驱动与内核交互
  • Spring AI Alibaba + JManus:从架构原理到生产落地的全栈实践——一篇面向 Java 架构师的 20 分钟深度阅读
  • 打造智能化应用新思路:扣子Coze工作流详解与最佳实践
  • MCU中的总线桥是什么?
  • js的基本内容:引用、变量、打印、交互、定时器、demo操作
  • 聚簇索引的优势
  • LeetCode|Day22|231. 2 的幂|Python刷题笔记
  • windows下nvm的安装及使用
  • 融云“通信+AI”解决方案三大场景实例
  • 使用mybatis实现模糊查询和精准查询切换的功能
  • GraphRAG的部署和生成检索过程体验
  • 小白成长之路-部署Zabbix7
  • 使用react编写一个简单的井字棋游戏
  • 17.VRRP技术
  • 接口自动化测试种涉及到接口依赖怎么办?
  • 微调大语言模型(LLM)有多难?
  • Google Gemini 体验
  • 深入解析Hadoop中的推测执行:原理、算法与策略
  • kafka查看消息的具体内容 kafka-dump-log.sh