前端搭建低代码平台,微前端如何选型?

目录

背景

一、微前端是什么?

二、三大特性

三、现有微前端解决方案

1、iframe

2、Web Components

3、ESM

4、EMP

5、Fronts

6、无界(文档)

7、qiankun

四、我们选择的方案

引入qiankun并使用(src外层作为主应用)

主应用使用qiankun

微应用工程要做什么

主应用&微应用通讯

FAQ

五、总结


背景

1.首先我们可以先来想一下,日常工作中我们是如何进行代码复用的?

  • 复制粘贴 Ctrl cv
  • 抽离封装模块
  • 打npm包

2.但是,以上方法,会存在哪些问题呢?

--复制粘贴

  • 增加重复的代码
  • 复用代码逻辑发生变动时需要处处修改
  • 违反 Don’t Repeat Yourself 原则

--抽离封装模块

  • 仅适用于当前项目,无法兼容多个项目要使用同一个模块的情景

--打npm包或库

  • 还蛮通用的…但是也有其他问题:
  • 发布效率低下
  • 当迭代npm包内的逻辑业务:发布npm包 -> 告诉其他使用的伙伴更新npm ->再各自构建发布一次 (繁琐极了)

于是微前端诞生了,用来将大型项目进行拆分和解耦。

一、微前端是什么?

微前端概念是从微服务概念扩展而来的,摒弃大型单体方式,将前端整体分解为小而简单的块。这些块可以独立开发、测试和部署,同时仍然聚合为一个产品出现在客户面前。

微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用后,随之而来产生的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。

二、三大特性

  • 无技术栈限制
  • 应用单独开发、测试和部署、交付
  • 多应用整合

三、现有微前端解决方案

1、iframe

iframe是html提供的标签,能加载其他web应用的内容,并且能兼容所有的浏览器。

不足:

  • 不是单页应用,会导致浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
  • 弹框类的功能无法应用到整个大应用中,只能在对应的窗口内展示。 由于可能应用间不是在相同的域内,主应用的 cookie要透传到根域名都不同的子应用中才能实现免登录效果。
  • 每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程,占用大量资源的同时也在极大地消耗资源。

经过以上思考,拓展总结: iframe的特性导致搜索引擎无法获取到其中的内容,进而无法实现应用的seo。

 2、Web Components 

Web Component 是一套不同的技术,允许你创建可重用的定制元素(它们的功能封装在你的代码之外),并且在你的 web 应用中使用它们。Web Component包括Custom Element、Shadow DOM、HTML templates 三种技术规范。

点击查看MDM对它的定义

Web Component具备微前端的几个特性:

  1. 技术栈无关:Web Components是浏览器原生组件,在任何框架中都可以使用。
  2. 样式隔离:使用 Shadow DOM 可以实现样式的完全隔离,防止不同组件之间的样式冲突。
  3. 可重用性:创建的 Web Component 可以在多个项目中重复使用,提高了代码的复用率。

不足:

  1. 对于不熟悉 Web Components 的开发者来说,学习和使用这些 API 可能有一定的学习曲线,需要理解 Shadow DOM、Custom Elements 和 HTML Templates 等概念。
  2. 缺少生态和社区支持,社区支持和文档资源相对较少,解决问题和获取帮助不如其他框架方便。

3、ESM

ESM是ES Module的缩写,是Ecma script 2015中提出的一种前端模块化手段

也是符合以下几点

  1. 无技术栈限制:ESM加载的只是js内容,无论哪个框架,最终都要编译成js。因此,无论哪种框架,ESM都能加载。
  2. 应用单独开发:ESM只是js的一种规范,不会影响应用的开发模式。
  3. 多应用整合:只要将微应用以ESM的方式暴露出来,就能正常加载。
  4. 远程加载模块: ESM能够直接请求cdn资源,这是它与生俱来的能力。

不足:兼容性问题

4、EMP

EMP是由欢聚时代业务中台自主研发的最年轻的单页微前端解决方案,除了具备微前端的能力外,还实现了跨应用状态共享、跨框架组件调用的能力。

具备以下几大特点:

  • 每个微应用独立部署运行 跨技术栈组件式调用。
  • 应用间通信,每一个应用都可以进行状态共享,就像在使用npm模块进行开发一样便捷。
  • 每个微应用独立部署运行

不足EMP的社区支持和文档可能不如其他成熟的微前端框架丰富。虽然EMP支持跨技术栈组件调用,但它主要基于Vue.js和Element UI。如果项目中需要使用其他框架或库,可能会遇到兼容性问题。

5、Fronts

Fronts 是一个基于 Webpack 的 Module Federation API 设计的渐进式微前端框架。它强调颗粒间的去中心化依赖管理,并支持多种运行模式来满足不同的微前端架构需求。

  • 支持非 Module Federation - 虽然 Fronts 基于 Module Federation 概念,但它依然支持任何传统且不支持 Module Federation 的前端应用。
  • 去中心化配置 - 只需要在每个 Fronts 应用中设置 site.json,就像设置一个 package.json 一样简单,Fronts 支持多层嵌套的微前端。
  • 跨框架 - 没有任何现代前端框架限定。
  • 代码分割/懒加载 - 支持在 Fronts 应用内进行代码拆分和导出共享模块,它可以被其他 Fronts 应用作为依赖模块进行懒加载。
  • CSS 隔离 - 可选的 CSS 隔离设定,并根据不同的渲染方式,有宽松隔离和严格隔离的可选项。
  • 生命周期 - 每个 Fronts 应用的 Entry 支持简洁的生命周期接口。
  • Web Components 和 iFrame - 支持多种前端运行时容器用于不同隔离环境的要求。
  • 多种构建模式 - 同时支持在微前端模式和非微前端模式构建,兼容动态化的运行时集成和静态化的构建时集成。
  • Monorepo 和 TypeScript - 良好支持 Monorepo 和 TypeScript,它们和 Fronts 是非常适合架构在一起的技术栈。
  • 版本控制 - Fronts 提供的版本控制可用于高效和动态的即时交付应用,当然也包括支持灰度发布。
  • 零劫持 - Fronts 不做任何执行容器上的环境全局公共 API 劫持,保持运行环境的原始性,避免可能带来的性能损失和安全问题。
  • 通用化消息通讯 - Fronts 提供简洁通用的响应式 API,它支持前端绝大部分原生 API。

不足:学习曲线较陡峭、构建时间可能较长。

6、无界(文档

基于 webcomponent 容器 + iframe 沙箱,能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户的核心诉求。

1.成本低:无界微前端的成本非常低,主要体现在主应用的使用成本、子应用的适配成本两个方面。

  • 主应用使用成本低:主应用使用无界不需要学习额外的知识,无界提供基于 vue 封装的 wujie-vue 和基于 react 封装的 wujie-react,用户可以当成普通组件一样加载子应用。
  • 子应用适配成本低:当运行的方式是重建模式时,子应用可以不做任何改造就在无界框架中运行,其他模式需要适当的做一些生命周期改造工作。

2.速度快无界微前端非常快,主要体现在首屏打开快、运行速度快两个方面

3.原生隔离无界微前端实现了 css 沙箱和 js 沙箱的原生隔离,子应用不用担心污染问题。

4.功能强大:无界微前端的功能非常强大,支持子应用保活、子应用内嵌、多应用激活、去中心化通信、生命周期、插件系统、vite 框架支持、兼容 IE9、应用共享。

不足iframe沙箱可能带来性能开销和通信复杂性,生命周期管理在复杂环境中可能变得更复杂。

7、qiankun

在微前端界,qiankun算得上是最早成型且知名度最广的框架了,它是真正意义上的单页微前端框架

具备以下几大特点:

  1. 基于single-spa封装,提供了更加开箱即用的 API
  2. 技术栈无关,任意技术栈的应用均可使用/接入,不论是 React/Vue/Angular/JQuery 还是其他的框架。
  3. HTML Entry 接入方式,让你接入微应用像使用 iframe 一样简单。
  4. 样式隔离,确保微应用之间样式互相不干扰。
  5. JS 沙箱,确保微应用之间全局变量/事件不冲突。
  6. 资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
  7. umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统
  8. 活跃的社区/文档支持。

不足qiankun是基于single-spa封装的,因此它的功能和限制也受到single-spa的影响。虽然提供了开箱即用的API,但对于复杂的微前端架构,配置和管理可能会变得复杂。

四、我们选择的方案

结合公司产品和现有项目的技术框架(vue2),我们采取的是qianku方案,首先我们的路由模式是hash模式,要将hash改成history。

为什么我们要把原本的hash改成history?

qiankun接入外部服务时,父容器需要适应路由方式history(当前开发平台为hash,即/#/)

-- hash路由:子应用也必须是hash路由,且需继承主应用的基础路径。

-- history路由:主应用如果是history,则子应用可以是history也可以是hash。

如何将路由从hash改成history?这个会再出一篇文章详细讲解,敬请期待。

引入qiankun并使用(src外层作为主应用)

1.安装qiankun依赖

yarn add qiankun # 或者 npm i qiankun -S

主应用使用qiankun

a.承载微应用(我们选择了创建容器的方式,可以根据实际情况来传递一些参数给微应用)

<template>
  <div class="info">
    <div @click="changeChildState">改变子路由状态(测试)</div>
    <!-- 目标容器 -->
    <div id="subapp-viewport"></div>
  </div>
</template>

<script>
import { registerMicroApps, start, initGlobalState } from 'qiankun'
export default {
  // 对应微应用的name
  name: 'apply-manage',
  data() {
    return {
      // 全局状态
      actions: null
    }
  },
  mounted() {
    // 传递给微应用的值
    const initialState = {
      router: '/test'
    }
    // 初始化全局状态(可选)
    this.actions = initGlobalState(initialState)
    // 注册微应用
    registerMicroApps([
      {
        // 微应用名字,需要和微应用的package.json的name一致/微应用全局导出的name一致
        name: 'apply-manage',
        // 微应用入口
        // 1、内部子模块直接指向对应的入口,到时候需要区分生产/本地
        // 2、外部应用直接指向其入口
        entry: 'http://localhost:8081/apply',
        // 触发加载微应用的路由
        activeRule: '/temApply',
        // 容器id
        container: '#subapp-viewport', // 子应用挂载的div,
        // 可选,需要传递给微应用的参数
        props: {
          test1: 'testtt'
        }
      }
    ], {
      // 下面是微应用加载时候的一些钩子函数
      beforeLoad: app => {
        console.log('before load app.name====>>', app.name)
      },
      beforeMount: [
        app => {
          console.log('[LifeCycle] before mount %c%s', 'color: green;', app.name)
        }
      ],
      afterMount: [
        app => {
          console.log('[LifeCycle] after mount %c%s', 'color: green;', app.name)
        }
      ],
      afterUnmount: [
        app => {
          console.log('[LifeCycle] after unmount %c%s', 'color: green;', app.name)
        }
      ]
    })
    // 改变传递给微应用时候会触发的函数
    this.actions.onGlobalStateChange((newState, prev) => {
      // state: 变更后的状态; prev 变更前的状态
      console.log('main change', JSON.stringify(newState), JSON.stringify(prev))
    })
    // 启动 qiankun
    start({
      // 沙箱隔离
      sandbox: true,
      // 可选,有第三方js引入时使用
      excludeAssetFilter: assetUrl => {
        // 白名单协议:子应用下如需要放行动态加载的css/js资源,可以在链接上带上参数 _custom-exclude_=MAIN
        const whiteWords = ['_custom-exclude_=MAIN']
        return whiteWords.some(w => {
          return assetUrl.includes(w)
        })
      }
    })
  },
  methods: {
    // 测试改变全局状态
    changeChildState() {
      // 按一级属性设置全局状态,微应用中只能修改已存在的一级属性,会同步到微应用
      this.actions.setGlobalState({
        router: 'routerNameMap[name]'
      })
    }
  },
  beforeDestroy() {
    // 移除当前应用的状态监听,微应用 umount 时会默认调用
    this.actions.offGlobalStateChange()
  }
}
</script>
<style lang="less" scoped>
</style>

b.设置容器对应的路由

路由后面的(.*)*需要携带,不然会微应用子路由会出现404

微应用工程要做什么

c.引入public-path.js

  • public-path.js
/* eslint-disable camelcase */
if (window.__POWERED_BY_QIANKUN__) {
  __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__
}
  • main.js
// 第一行
import './public-path'
xxxx

d.导出相应的生命周期钩子

main.js


// 第一行
import './public-path'
let instance = null
function render(props) {
  // 作为独立项目
  if (!props) {
    /* eslint-disable no-new */
    new Vue({
      router,
      store,
      render: h => h(App)
    }).$mount('#app')
    return
  }
  // 作为微应用时
  const { container, usePicker } = props
  instance = new Vue({
    router,
    store,
    data() {
      return {
        usePicker
      }
    },
    render: h => h(App)
  }).$mount(container ? container.querySelector('#app') : '#app')
  // if (props.router) {
  //   router.push({
  //     name: props.router
  //   })
  // }
}
// 独立运行时
if (!window.__POWERED_BY_QIANKUN__) {
  render()
}

(global => {
  // apply-manage跟主应用加载微应用时候的name一致
  global['apply-manage'] = {
    bootstrap: () => {
      return Promise.resolve()
    },
    mount: (props) => {
      // 全局状态更改时候触发
      props.onGlobalStateChange(state => {
        // setTimeout(() => {
        // router.push({
        //   name: state.router
        // })
        // }, 500)
      }, true)
      return render(props)
    },
    unmount: () => {
      instance.$destroy()
      return Promise.resolve()
    }
  }
})(window)

e.如果是history模式的话,要设置routerbase为主应用那边的触发路由

主应用容器

微应用

f.需要区分好独立运行和作为微应用运行时候的各项功能配置

例子:独立运行要登录,作为微应用时候直接获取主应用的登录状态等等

主应用&微应用通讯

g.思路

主应用采用原生方式实现订阅机制(以下称为eventBus),并挂载在window上,使主&子应用共用一份eventBus机制。

h.实现

这个会再出一篇文章详细讲解,敬请期待。

FAQ

官网常见文集文档:常见问题 - qiankun

1.使用第三方链接报跨域

· 解决方案:手动加载

2.父子组件中加载两个monaco编辑器,其中实例放在data中会页面卡死

· 方案:将editor属性从data移除

3.主应用&微应用通讯规范

五、总结

对于低代码平台,推荐优先考虑 qiankun,因为它提供了技术栈无关性、样式隔离、JS沙箱、跨应用通信、性能优化以及活跃的社区支持。这些特性使得qiankun非常适合需要支持多种技术栈和高度可扩展性的低代码平台。

如果你的项目需要更细粒度的控制和更复杂的配置,可以考虑 fronts,它提供了更多的灵活性和高级功能,但需要更多的配置和学习成本。

如果你特别关注低成本和快速集成,并且对iframe沙箱带来的限制能够接受,那么 无界 也是一个不错的选择。

最终的选择应该基于你的具体需求、团队的技术栈和经验,以及项目的长期发展规划。


点点关注,下期精彩继续!

道一云七巧-与你在技术领域共同成长

更多技术知识分享:https://bbs.qiqiao668.com/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/915964.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CVE-2024-2961漏洞的简单学习

简单介绍 PHP利用glibc iconv()中的一个缓冲区溢出漏洞&#xff0c;实现将文件读取提升为任意命令执行漏洞 在php读取文件的时候可以使用 php://filter伪协议利用 iconv 函数, 从而可以利用该漏洞进行 RCE 漏洞的利用场景 PHP的所有标准文件读取操作都受到了影响&#xff1…

InternVL 多模态模型部署微调实践

目录 0 什么是MLLM 1 开发机创建与使用 2 LMDeploy部署 2.1 环境配置 2.2 LMDeploy基本用法介绍 2.3 网页应用部署体验 3 XTuner微调实践 3.1 环境配置 3.2.配置文件参数解读 3.3 开始微调 4.体验模型美食鉴赏能力 0 什么是MLLM 多模态大语言模型 ( Multimodal Larg…

干货分享之Python爬虫与代理

嗨伙伴们&#xff0c;今天是干货分享哦&#xff0c;可千万不要错过。今天小蝌蚪教大家使用phthon时学会巧妙借用代理ip来更好地完成任务。 让我们先了解一下为什么说咱们要用爬虫代理ip呢&#xff0c;那是因为很多网站为了防止有人过度爬取数据&#xff0c;对自身资源造成损害…

鸿蒙学习生态应用开发能力全景图-赋能套件(1)

文章目录 赋能套件鸿蒙生态应用开发能力全景图 赋能套件 鸿蒙生态白皮书: 全面阐释了鸿蒙生态下应用开发核心理念、关键能力以及创新体验,旨在帮助开发者快速、准确、全面的了解鸿蒙开发套件给开发者提供的能力全景和未来的愿景。 视频课程: 基于真实的开发场景,提供向导式…

netcat工具安装和使用

netcat是一个功能强大的网络实用工具&#xff0c;可以从命令⾏跨⽹络读取和写⼊数据。 netcat是为Nmap项⽬编写的&#xff0c;是⽬前分散的Netcat版本系列的经典。 它旨在成为可靠的后端⼯具&#xff0c;可⽴即为其他应⽤程序和⽤户提供⽹络连接。 一&#xff0c;下载安装 1&a…

【PHP】ThinkPHP基础

下载composer ComposerA Dependency Manager for PHPhttps://getcomposer.org/ 安装composer 查看composer是否安装 composer composer --version 安装 ThinkPHP6 如果你是第一次安装的话&#xff0c;首次安装咱们需要打开控制台&#xff1a; 进入后再通过命令,在命令行下面&a…

【HarmonyOS】应用实现读取剪切板内容(安全控件和自读取)

【HarmonyOS】应用实现读取粘贴板内容(安全控件和自读取) 前言 三方应用 读取系统剪切板是比较常见的功能。可以实现功能入口的快捷激活跳转&#xff0c;以及用户粘贴操作的简化&#xff0c;增强用户的体验感。 但是在用户日渐注重隐私的今天&#xff0c;系统对于剪切板权限的…

飞牛云fnOS本地部署WordPress个人网站并一键发布公网远程访问

文章目录 前言1. Docker下载源设置2. Docker下载WordPress3. Docker部署Mysql数据库4. WordPress 参数设置5. 飞牛云安装Cpolar工具6. 固定Cpolar公网地址7. 修改WordPress配置文件8. 公网域名访问WordPress 前言 本文旨在详细介绍如何在飞牛云NAS上利用Docker部署WordPress&a…

解析安卓镜像包和提取DTB文件的操作日志

概述 想查看一下安卓的镜像包里都存了什么内容 步骤 使用RKDevTool_v3.15对RK3528_DC_HK1_RBOX_K8_Multi_WIFI_13_20230915.2153.img解包 路径: 高级(Advancing) > 固件(firmware) > 解包(unpacking)得到\Output\Android\Image boot.imguboot.imgsuper.img 处理boot.…

LeetCode 热题100(八)【二叉树】(3)

目录 8.11二叉树展开为链表&#xff08;中等&#xff09; 8.12从前序与中序遍历序列构造二叉树&#xff08;中等&#xff09; 8.13路径总和III&#xff08;中等&#xff09; 8.14二叉树的最近公共祖先&#xff08;中等&#xff09; 8.15二叉树中的最大路径和&#xff08;困…

FPGA实现PCIE3.0视频采集转SDI输出,基于XDMA+GS2971架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案本博已有的 SDI 编解码方案本博客方案的PCIE2.0版本 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存Native视频时序生成RGB转BT1120SDI转HDM…

纽约大学:指导LLM提出澄清性问题

&#x1f4d6;标题&#xff1a;Modeling Future Conversation Turns to Teach LLMs to Ask Clarifying Questions &#x1f310;来源&#xff1a;arXiv, 2410.13788 &#x1f31f;摘要 &#x1f538;大型语言模型&#xff08;LLM&#xff09;必须经常对高度模糊的用户请求做出…

STM32F1学习——I2C通信

一、I2C通信一带多 在学习通信的时候&#xff0c;我们常会听到串口通信。但串口通信只限定两个设备之间&#xff0c;如果有多个设备&#xff0c;通信的两个设备就要连接上&#xff0c;接线复杂。所以有了总线式通信&#xff0c;在一条总线上可以连接多个设备&#xff0c;这些根…

当你想要conda安装遇到UnavailableInvalidChannel: HTTP 404 NOT FOUND for channel的问题

想要装个虚拟环境&#xff0c;结果遇到404。 看了第一个GitHub帖子中的一句话 UnavailableInvalidChannel: The channel is not accessible or is invalid. Navigator not launching. Issue #9473 conda/conda GitHub 想说那我就把这个not found的channel删掉吧&#xff…

Jmeter中的前置处理器(一)

前置处理器 1--JSR223 PreProcessor 功能特点 自定义数据处理&#xff1a;使用脚本语言处理请求数据&#xff0c;实现高度定制化的数据处理和生成。动态数据生成&#xff1a;在请求发送前生成动态数据&#xff0c;如随机数、时间戳等。变量设置&#xff1a;设置和修改 JMeter…

2023年高校大数据挑战赛A题中文文本纠错求解全过程文档及程序

2023年高校大数据挑战赛 A题 中文文本纠错 原题再现&#xff1a; 中文文本纠错的任务主要是针对中文文本中出现的错误进行检测和纠正&#xff0c;属于人工智能自然语言处理的研究子方向。中文文本纠错通常使用的场景有政务公文、裁判文书、新闻出版等&#xff0c;中文文本纠错…

使用CNN进行验证码识别:深度学习与图像预处理教程

验证码&#xff08;CAPTCHA&#xff09;广泛用于区分人类和自动化程序&#xff08;如机器人&#xff09;&#xff0c;通常由扭曲的字母、数字或符号组成。为了实现验证码的自动识别&#xff0c;深度学习尤其是卷积神经网络&#xff08;CNN&#xff09;非常有效。本文将带你一起…

基于 Python Django 的二手房间可视化系统分析

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

探索 Sentinel 服务容错

Sentinel 是阿里巴巴开源的一款高可用防护组件,主要用于分布式系统中的流量控制、熔断降级和系统负载保护。它在 Java 微服务架构中扮演着重要的角色,帮助开发者确保系统的稳定性和可靠性。 以下是 Sentinel 的一些关键特性: 流量控制(Flow Control):通过对请求进行限流…

DBeaver 连接 OceanBase Oracle 租户

DBeaver 是一款通用的数据库工具软件&#xff0c;支持任何具有JDBC驱动程序的数据库。DBeaver 需要 Java 运行环境的支持。截稿时 DBeaver 24.0.0 版本默认提供的 OceanBase 驱动是连接 MySQL 的&#xff0c;想连接 Oracle 租户需要新建一个驱动器使用。 下载数据库驱动包 1、…