阅读 836

微前端学习系列(一):微前端介绍

image.png

目录

前言

当前,基于 vuereactangular单页应用开发模式已经成为业界主流。受益于它们丰富的生态,我们可以使用这些技术快速构建一个新的应用,迅速响应市场。随着公司业务的不断发展,应用开始变得庞大臃肿,逐渐成为一个巨石应用,难以维护不说,每次开发、上线新需求时还需要花费不少的时间来构建项目,对开发人员的开发效率和体验都造成了不好的影响。因此将一个巨石应用拆分为多个子应用势在必行。

一般情况下,我们会基于业务来拆分应用。每个应用都有一个自己的仓库,独立开发独立部署独立访问独立维护,还可以根据团队的特点自主选择适合自己的技术栈,极大的提升了开发人员的效率和体验。

应用拆分能给我们带来便利,但同时也给我们带来了新的挑战,那就是应用的聚合。对于客户来说,他们在使用我们的产品时,更希望呈现在自己面前的是一个完整的应用,而不是分散的多个子应用。因此我们需要选择一个合适的方案,能兼容不同的技术栈,将已经拆分的子应用重新聚合。

微前端,正是这样一个合适的方案,来帮助我们面对上述挑战。

什么是微前端

微前端,早已是一个老生常谈的概念,它于 2016 年首次出现在 ThoughtWorks Technology Radar 上,将后端微服务的概念扩展到了前端世界。

微服务,维基上对其定义为:一种软件开发技术- 面向服务的体系结构(SOA)架构样式的一种变体,将应用程序构造为一组松散耦合的服务,并通过轻量级的通信协议组织起来。具体来讲,就是将一个单体应用,按照一定的规则拆分为一组服务。这些服务,各自拥有自己的仓库,可以独立开发、独立部署,有独立的边界,可以由不同的团队来管理,甚至可以使用不同的编程语言来编写。但对前端来说,仍然是一个完整的服务。

微服务,主要是用来解决庞大的一整块后端服务带来的变更和扩展的限制

同样的,面对越来越重的前端应用,可将微服务的思想照搬到前端,就有了微前端的概念。像微服务一样,一个前端应用,也可以按照一定的规则,拆分为不同的子应用,独立开发,独立部署,然后聚合成一个完整的应用面对客户。

微前端的一般结构如下:

上图摘取自 微前端到底是什么

微前端能带给我们什么

  • 简单、分离、松耦合的代码仓库

    对比巨石应用一整块的代码仓库,微前端架构下的代码仓库更加简单轻量。各个仓库的代码可以基于业务权限变更的频率组织结构后端微服务等原则拆分,界限明确降低耦合,便于开发人员在开发过程中快速定位源代码,提高开发效率,降低维护成本。

  • 独立开发、独立部署

    代码库拆分以后,我们可以基于各个代码仓库独立开发。由于代码体积的缩小,项目构建时间变短,极大提升开发效率。

    另外,各个项目都有自己的交付流水线(从构建、测试到上线),并且能够独立部署,不需要考虑其他项目的情况。

  • 技术栈无关

    在实际项目中,各个项目会因为各种各样的原因导致使用的技术栈不一样。比如开发框架有 reactvueangular 等,构建工具有 webpackrollupparcel 等,而且版本还可能不一致。使用微前端架构,可以做到将使用不同技术栈(不同版本)的子应用聚合起来

  • 遗留系统迁移

    每个公司中,多多少少会存在一些应用是使用老的技术栈开发的,比如 Backbone、Vue1.0、angular2、jquery 等。这些应用已经在线上稳定运行,而且也没有新的功能。对于这样的应用,我们没有理由浪费时间和精力,可以通过微前端方案直接整合到新的应用中。

    使用微前端方案很大一部分原因就是为了解决遗留系统迁移问题。

  • 技术栈升级

    除了遗留系统迁移,微前端在技术栈版本升级方面也能提供帮助。

    有些项目,在成立之初使用了当前最新的技术如 antd2。随着技术的发展,antd 已经更新到了 4,但项目由于一直在迭代,还是使用 antd2。直接全部重构,肯定是不现实的,费时费力不说,风险也大。

    针对这种情况,我们可以重起一个应用,使用 antd4 循序渐进的重构应用,然后使用微前端方案将新旧应用聚合在一起。

  • 团队技术成长

    微前端技术栈无关的优点,可以让团队获得更多的机会在项目中尝试新的技术(vue3、webpack5 等),有助于整个团队技术的成长。

使用微前端时面临的挑战

微前端方案给我们带来巨大便利的同时,也给我们带来了新的挑战。在实现微前端应用时,我们必须要考虑以下问题:

  • 子应用切换;
  • 应用相互隔离,互不干扰;
  • 子应用之间通信;
  • 多个子应用并存;
  • 用户状态的存储 - 免登;

微前端常用技术方案

目前,业界主流的微前端实现方案主要有:

  • 路由分发式微前端
  • iframe
  • single-spa
  • qiankun
  • webpack5:module federation
  • Web Component

路由分发式微前端

路由分发式微前端,即通过路由将不同的业务分发到不同的独立前端应用上。最常用的方案是通过 HTTP 服务的反向代理来实现。

下面是一个基于路由分发的 Nginx 配置:

 http {
        server {
            listen 80;
            server_name  xxx.xxx.com;
            location /api/ {
                proxy_pass http://localhost:3001/api;
            }
            location /web/admin {
                proxy_pass http://localhost:3002/api;
            }
            location / {
                proxy_pass /;
            }
        }
    }
复制代码

通过上述配置,不同页面的请求就可以分发到不同的服务器上。

优点

  • 实现简单;
  • 不需要对现有应用进行改造;
  • 完全技术栈无关;

缺点

  • 用户体验不好,每次切换应用时,浏览器都需要重新加载页面;
  • 多个子应用无法并存;
  • 局限性比较大;
  • 子应用之间的通信比较困难;
  • 子应用切换时需要重新登录;

iframe

iframe 作为一项非常古老的技术,也可以用于实现微前端。通过 iframe,我们可以很方便的将一个应用嵌入到另一个应用中,而且两个应用之间的 css 和 javascript 是相互隔离的,不会互相干扰。

优点:

  • 实现简单;
  • css 和 js 天然隔离,互不干扰;
  • 完全技术栈无关;
  • 多个子应用可以并存;
  • 不需要对现有应用进行改造;

缺点:

  • 用户体验不好,每次切换应用时,浏览器需要重新加载页面;
  • UI 不同步,DOM 结构不共享;
  • 全局上下文完全隔离,内存变量不共享,子应用之间通信、数据同步过程比较复杂;
  • 对 SEO 不友好;
  • 子应用切换时可能需要重新登录,体验不好;

single-spa

路由转发模式iframe 模式尽管可以实现微前端,但是体验不好。我们每次切换回已经访问过的子应用时,都需要重新加载子应用,对性能有很大的影响。

我们知道,现在前端应用开发的主流模式为基于 vue / react/ angular单页应用开发模式。在这种模式下,我们需要维护一个路由注册表,每个路由对应各自的页面组件 url切换路由时,如果是一个新的页面,需要动态获取路由对应的 js 脚本,然后执行脚本并渲染出对应的页面;如果是一个已经访问过的页面,那么直接从缓存中获取已缓存的页面方法,执行并渲染出对应的页面。

那么,微前端也有没有类似的实现方案,来获得和单页应用一样的用户体验呢?

答案是有的。 single-spa 提供了新的技术方案,可以帮忙我们实现类似单页应用的体验。

single-spa 方案中,应用被分为两类:基座应用子应用。其中,子应用就是文章上面描述的需要聚合的子应用;而基座应用,是另外的一个单独的应用,用于聚合子应用

和单页应用的实现原理类似,single-spa 会在基座应用中维护一个路由注册表每个路由对应一个子应用。基座应用启动以后,当我们切换路由时,如果是一个新的子应用,会动态获取子应用的 js 脚本,然后执行脚本并渲染出相应的页面;如果是一个已经访问过的子应用,那么就会从缓存中获取已经缓存的子应用,激活子应用并渲染出对应的页面。

在这里,本文仅对 single-spa 做初步的介绍,如需深入了解,详见 官网:single-spa微前端学习系列(二):single-spa

优点:

  • 切换应用时,浏览器不用重载页面,提供和单页应用一样的用户体验;
  • 完全技术栈无关;
  • 多个子应用可并存;
  • 生态丰富;

缺点:

  • 需要对原有应用进行改造,应用要兼容接入 sing-spa 和独立使用;
  • 有额外的学习成本;
  • 使用复杂,关于子应用加载、应用隔离、子应用通信等问题,需要框架使用者自己实现;
  • 子应用间相同资源重复加载;
  • 启动应用时,要先启动基座应用;

qiankun

single-spa 一样,qiankun 也能给我们提供类似单页应用的用户体验。qiankun 是在 single-spa 的基础上做了二次开发,在框架层面解决了使用 single-spa 时需要开发人员自己编写子应用加载、通信、隔离等逻辑的问题,是一种比 single-spa 更优秀的微前端方案。

在这里,本文同样仅对 qiankun 做简单的说明,如需深入了解,详见 官网:qiankun微前端学习系列(三):qiankun

优点:

  • 切换应用时,浏览器不用重载页面,提供和单页应用一样的用户体验;
  • 相比 single-spa,解决了子应用加载、应用隔离、子应用通信等问题,使用起来相对简单;
  • 完全和技术栈无关;
  • 多个子应用可并存;

缺点:

  • 需要对原有应用进行改造,应用要兼容接入 qiankun 和独立使用;
  • 有额外的学习成本;
  • 相同资源重复加载;
  • 启动应用时,要先启动基座应用;

webpack5:module federation

新发布的 webpack5,提供了一个新的特性 - module federation。基于这个特性,我们可以在一个 javascript 应用中动态加载并运行另一个 javascript 应用的代码,并实现应用之间的依赖共享

通过 module federation,我们可以在一个应用里面动态渲染另一个应用的页面,这样也就实现了多个子应用的聚合

module federation 的用法详见 微前端学习系列(四): module federation

优点:

  • 不需要对原有应用进行改造,只需改造打包脚本;
  • 切换应用时,浏览器不用重载页面,提供和单页应用一样的用户体验;
  • 多个子应用可并存;
  • 相同资源不需要重复加载;
  • 开发技术栈无关;
  • 应用启动后,无需加载与自己无关的资源;
  • 免登友好;

缺点:

  • 构建工具只能使用 webpack5;
  • 有额外的学习成本;
  • 对老项目不友好,需要对 webpack 进行改造;

Web Component

基于 Web ComponentShadow Dom 能力,我们也可以实现微前端,将多个子应用聚合起来。

Shadow Dom 的用法如下:

const shadow = document.querySelector('#hostElement').attachShadow({mode: 'open'});
// url 为应用的地址,基于 fetch,我们可以获取到应用的 html 模板,添加到指定节点下
fetch(url).then(res => {
    shadow.innerHTML = res
});
复制代码

优点:

  • 实现简单;
  • css 和 js 天然隔离,互不干扰;
  • 完全技术栈无关;
  • 多个子应用可以并存;
  • 不需要对现有应用进行改造;

缺点:

  • 主要是浏览器兼容性问题
  • 开发成本较高;

结束语

到这里,微前端的介绍就结束了。本文是微前端学习系列的开篇,之后我们会陆续推出微前端学习系列: single-spa微前端学习系列: qiankunmodule federation, 希望通过这些文章的学习,能让大家对微前端有一个比较深刻的认识,😁。

本文的参考资料:

文章分类
前端
文章标签