微前端理论与落地

370 阅读5分钟
前言

微前端(Micro-Frontends)它是将“微服务”的概念拓展到了前端领域。它没有定义框架、API,它是一个类似“微服务架构”的概念。

从前端的角度换句话来说,微前端就是将一个大型应用拆分为多个轻量的、功能独立且与技术栈无关的前端应用。 这样每个前端应用可以独立部署、升级、维护以及开发。

使用微前端为我们带来了什么?
1.在技术选择上的灵活

由于与技术栈无关的特性,主应用与微应用都可以灵活的选择不同的技术栈进行开发。

po8xme6IhJubxZ_gAjMTD7KCWy1cdN0pjP-k5XeUeDs.png

2.并行开发与团队自治

由于拆分为多个子应用,子应用间的开发可以单团队多人(多团队多人)并行开发。多个子应用可以由不同的团队来进行开发与管理,团队对应用的规划与代码的管理更加的自治。

不同的子应用由不同的团队负责,他们能够有效且快速的从用户角度出发,围绕业务功能去做垂直开发(业务的颗粒化),而不是围绕技术去做扩展,这样也会给团队带来更高的 凝聚力

L_LU3jjT6AyX55-WiO2TXkOGkamN0jQU5mlwRsd8bq8.png

3.项目的增量升级

在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略。

4.构建速度的提升

由一个大型应用拆分为多个轻量型应用,当对单个项目中的前端代码变少很多,在前端打包构建的时候,构建工具处理的文件量减少,打包速度也得到了提升。

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

微前端技术方案对比
1.路由分发式微前端

将大型项目拆分为多个前端服务,然后通过Nginx配置代理,主应用在域名根目录下,不同的路径代理到不同的前端服务,这是一个很早期的方案。

这种方案,更多的像是用多个前端应用的聚合。他们看上去像是一个完整的应用,其实不然。当从应用A跳转到应用B时,往往会需要刷新一下浏览器,用户体验感较差。

优点:

  • 实施简单、快速

缺点:

  • 切换应用时浏览器刷新,体验较差。
  • 如果各应用间UI不统一,整体的割裂感会比较强。
2.iframe内联嵌入式

使用元素可以很方便的嵌入其他的页面到当前页面中。这是一个很古老的技术,却一直很管用。

优点:

  • 子应用之间天然隔离,互不影响。
  • 只要每个iframe来自同一个源,就可以使用postMessage API来进行消息的传递。
  • 易上手,实现简单。

缺点:

  • iframe中的URL状态信息不能同步到主应用,无法使用浏览器的前进后退功能。
  • 全局弹框无法很好的居中展示。
  • 主应用以子应用上下文完全隔离,内存变量不共享。
  • 每一次进入子应用都是一次浏览器上下文重建、资源加载的过程。
3.qiankun.js

qiankun 是一个基于 single-spa 的微前端实现库。他在主应用中注册并启动子应用,在子应用中需要做几个修改才可以正常工作。

  1. 新增 public-path.js 文件,用于修改运行时的 publicPath

  2. 微应用建议使用 history 模式的路由,需要设置路由 base,值和它的 activeRule 是一样的。

  3. 在入口文件最顶部引入 public-path.js,修改并导出三个生命周期函数。

  4. 修改构建工具,允许开发环境跨域和 umd 打包。

4.micro-app

micro-app是由京东前端团队推出的一款微前端框架,它借鉴了WebComponent的思想,通过js沙箱样式隔离元素隔离路由隔离模拟实现了ShadowDom的隔离特性,并结合CustomElement将微前端封装成一个类WebComponent组件,从而实现微前端的组件化渲染。

5.qiankun.js与micro-app对比

56DuGJFC-VTjP6ik60G6SonLXbTmuYGr-_Oia0JQDto.jpg

通过对比我们不难发现,micro-app为开发者提供了更完善的功能,接入成本也是较低的。目前没有一个完美的方案来解决前端页面(或者说子系统)接入第三方系统,技术方案选型本就是做一次取舍。

微前端在项目中落地

最终我们选择使用macro-app来落地微前端。

主应用

首先,在主应用中安装相关依赖:

npm i @micro-zoe/micro-app --save

依赖安装完毕后,在项目的入口文件中初始化micro-app

import microApp from '@micro-zoe/micro-app'

microApp.start()

如果当前项目采用typescript 来进行开发,还需要在src文件夹下增加types.d.ts 文件来拓展Window 的类型:

// types.d.ts
import { MicroApp } from "@micro-zoe/micro-app";

declare global {
  interface Window {
    microApp: MicroApp;
  }
}

否则在使用typescript 进行开发的项目中,从window 上获取microApp属性会出现报错:类型“Window & typeof globalThis”上不存在属性“microApp”。

接下来,我们在主应用中嵌入子应用:

React:

export function MyPage () {
  return (
    <div>
      <h1>子应用👇</h1>
      // name:应用名称, url:应用地址
      <micro-app name='my-app' url='http://localhost:3000/'></micro-app>
    </div>
  )
}

Vue:

<template>
  <div>
    <h1>子应用👇</h1>
    <!-- name:应用名称, url:应用地址 -->
    <micro-app name='my-app' url='http://localhost:3000/'></micro-app>
  </div>
</template>
子应用

在webpack-dev-server的headers中设置跨域支持。

devServer: {
  headers: {
    'Access-Control-Allow-Origin': '*',
  }
},

如果构建工具是使用vite ,那么不用单独设置子应用的跨域。