核心原理

MicroApp 的核心功能在 CustomElement 基础上进行构建,CustomElement 用于创建自定义标签,并提供了元素的渲染、卸载、属性修改等钩子函数,我们通过钩子函数获知微应用的渲染时机,并将自定义标签作为容器,微应用的所有元素和样式作用域都无法逃离容器边界,从而形成一个封闭的环境。

实践

创建 基座应用 与 子应用

  1. micro-app 不推荐使用 vite 项目作为 子应用,所以 vite + vue3 的用户会很很亏,只能通过 vue-cli 的形式去创建 vue3 项目。
    也可以使用 vite ,但是需要手动把沙箱功能关闭,因为不支持 vite 的 module script

  2. 基座应用不需要考虑用的什么技术,主要考虑在子应用。

  3. 子应用记得把 CORS 规则放开。因为 micro-app 是通过访问 url 的形式去获取资源的。

// vue.config.js
module.exports = {
  devServer: {
    headers: {
      "Access-Control-Allow-Origin": "*"
    }
  }
};
  1. 基座应用的代码
<!-- 
    name 你子应用名称,在通信时很重要
    url 路由地址
    baseroute 子应用的路由前缀,匹配 url 后的路由,如果对应不上,就只能加载子应用的第一个页面
 -->
<micro-app name="app1" url="http://xxxx.com" baseroute="/xxx"></micro-app>

路由控制

  1. 建议 基座 和 子应用 都用 history 模式。
    如果 基座 应用用的是 hash 模式,子应用只能是 history 模式了,为了后续的可持续发展,建议都只用 history 模式。避免不必要的路由冲突。

  2. 关于路由 path 末尾的 ‘/‘
    比如:’/pageA’ 和 ‘/pageA/‘ 实际指的是两个页面,在做路由配置的时候,不要漏了没有 ‘/‘ 的页面
    在 vue-router 3 下

{
    path: '/sub-page',
    name: 'subPage',
    component: function () {
      return import(/* webpackChunkName: "subPage" */ '../views/subPage.vue')
    }
  },
  {
    // * 通配符是指匹配任意一个子路由
    path: '/sub-page/*',
    name: 'subPage',
    component: function () {
      return import(/* webpackChunkName: "subPage" */ '../views/subPage.vue')
    }
  }

打包

  1. 为了避免打包后会出现意料之外的 404 问题,建议所有的开发环境在资源路径上要做到一致性。
    即:publicPath 的一致性
module.exports = {
  outputDir: "my-app",
  publicPath: process.env.NODE_ENV === "production" ? "/my-app/" : "", // bad ❌
  publicPath: "/my-app/" // good 👍
};

小技巧

巧用应用通信,修改基座 url ,方便在测试环境进行调试。
通过监听 @datachange 事件去修改基座的 url,从而实现子应用指向本地,方便本地代码测试。

子应用:

window.microApp.dispatch({ type: "子应用发送的数据" });

基座:

<micro-app
  @datachange="cb"
></micro-app>

cb(e) {
  console.log("来自子应用的数据:", e.detail.data);
  // 修改 url 
}

  1. 如无必要子应用别用 vite ,除非关闭沙箱模式
  2. 路由控制。参考上面
  3. 打包注意路径,尽量保证各个环境都一致。
  4. 兼容性。micro-app依赖于CustomElements和Proxy(目前不可polyfill)两个较新的API。
  5. name 重复造成冲突。可以使用 配置表 配置。

微前端的发展进程之 为什么不用 iFrame

为什么不用 iframe,这几乎是所有微前端方案第一个会被 challenge 的问题。但是大部分微前端方案又不约而同放弃了 iframe 方案,自然是有原因的,并不是为了 “炫技” 或者刻意追求 “特立独行”。

如果不考虑体验问题,iframe 几乎是最完美的微前端解决方案了。

iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。

  1. url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
  2. UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
  3. 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
  4. 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。

其中有的问题比较好解决(问题1),有的问题我们可以睁一只眼闭一只眼(问题4),但有的问题我们则很难解决(问题3)甚至无法解决(问题2),而这些无法解决的问题恰恰又会给产品带来非常严重的体验问题, 最终导致我们舍弃了 iframe 方案。



微前端 Micro-App

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!