抱歉,你查看的文章不存在

新轮子 Mooa:使用 mooa 微服务化 Angular 应用

Angular 基于 Component 的思想,可以让其在一个页面上同时运行多个 Angular 应用;可以在一个 DOM 节点下,存在多个 Angular 应用,即类似于下面的形式:

<app-home _nghost-c3="" ng-version="5.2.8"> <app-help _nghost-c0="" ng-version="5.2.2" style="display:block;"><div _ngcontent-c0=""></div></app-help> <app-app1 _nghost-c0="" ng-version="5.2.3" style="display:none;"><nav _ngcontent-c0="" class="navbar"></div></app-app1> <app-app2 _nghost-c0="" ng-version="5.2.2" style="display:none;"><nav _ngcontent-c0="" class="navbar"></div></app-app2></app-home>

可这一样一来,难免需要做以下的一些额外的工作:

  • 创建子应用项目模板,以统一 Angular 版本
  • 构建时,删除子应用的依赖
  • 修改第三方模块

而在这其中最麻烦的就是第三方模块冲突问题。思来想去,在三月中旬,我在 Mooa 中添加了一个 iframe 模式。

Mooa

Mooa 是一个为 Angular 服务的微前端框架,它是一个基于 single-spa,针对 IE 10 及 IFRAME 优化的微前端解决方案。

Mooa 框架与 Single-SPA 不一样的是,Mooa 采用的是 Master-Slave 架构,即主-从式设计。

对于 Web 页面来说,它可以同时存在两个到多个的 Angular 应用:其中的一个 Angular 应用作为主工程存在,剩下的则是子应用模块。

  • 主工程,负责加载其它应用,及用户权限管理等核心控制功能。
  • 子应用,负责不同模块的具体业务代码。

在这种模式下,则由主工程来控制整个系统的行为,子应用则做出一些对应的响应。

iframe 微服务架构设计

在这里,总的设计思想和之前的《如何解构单体前端应用——前端应用的微服务式拆分》中介绍是一致的:

Mooa 架构

主要过程如下:

  • 主工程在运行的时候,会去服务器获取最新的应用配置。
  • 主工程在获取到配置后,将一一创建应用,并为应用绑定生命周期。
  • 当主工程监测到路由变化的时候,将寻找是否有对应的路由匹配到应用。
  • 当匹配对对应应用时,则创建或显示相应应用的 iframe,并隐藏其它子应用的 iframe。

其加载形式与之前的 Component 模式并没有太大的区别:

Mooa Component 加载

而为了控制不同的 iframe 需要做到这么几件事:

  1. 为不同的子应用分配 ID
  2. 在子应用中进行 hook,以通知主应用:子应用已加载
  3. 在子应用中创建对应的事件监听,来响应主应用的 URL 变化事件
  4. 在主应用中监听子程序的路由跳转等需求

因为大部分的代码可以与之前的 Mooa 复用,于是我便在 Mooa 中实现了相应的功能。

微前端框架 Mooa 的特制 iframe 模式

iframe 可以创建一个全新的独立的宿主环境,这意味着我们的 Angular 应用之间可以相互独立运行,我们唯一要做的是:建立一个通讯机制

它可以不修改子应用代码的情况下,可以直接使用。与此同时,它在一般的 iframe 模式进行了优化。使用普通的 iframe 模式,意味着:我们需要加载大量的重复组件,即使经过 Tree-Shaking 优化,它也将带来大量的重复内容。如果子应用过多,那么它在初始化应用的时候,体验可能就没有那么友好。但是与此相比,在初始化应用的时候,加载所有的依赖在主程序上,也不是一种很友好的体验。

于是,我就在想能不能创建一个更友好地 IFrame 模式,在里面对应用及依赖进行处理。如下,就是最后生成的页面的 iframe 代码:

<app-home _nghost-c2="" ng-version="5.2.8"> <iframe frameborder="" width="100%" height="100%" src="http://localhost:4200/assets/iframe.html" id="help_206547" style="display:block;"></iframe> <iframe frameborder="" width="100%" height="100%" src="http://localhost:4200/assets/iframe.html" id="app_235458 style="display:none;"></iframe></app-home>

对,两个 iframe 的 src 是一样的,但是它表现出来的确实是两个不同的 iframe 应用。那个 iframe.html 里面其实是没有内容的:

<!doctype html><html lang="en"><head> <meta charset="utf-8"> <title>App1</title> <base href="/"> <meta name="viewport" content="width=device-width,initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"></head><body></body></html>

(PS:详细的代码可以见 https://github.com/phodal/mooa)

只是为了创建 iframe 的需要而存在的,对于一个 Angular 应用来说,是不是一个 iframe 的区别并不大。但是,对于我们而言,区别就大了。我们可以使用自己的方式来控制这个 IFrame,以及我们所要加载的内容。如:

  • 共同 Style Guide 中的 CSS 样式。如,在使用 iframe 集成时,移除不需要的
  • 去除不需要重复加载的 JavaScript。如,打包时不需要的 zone.min.js、polyfill.js 等等

注意:对于一些共用 UI 组件而言,仍然需要重复加载。这也就是 iframe 模式下的问题。

微前端框架 Mooa iframe 通讯机制

为了在主工程与子工程通讯,我们需要做到这么一些事件策略:

发布主应用事件

由于,我们使用 Mooa 来控制 iframe 加载。这就意味着我们可以通过 document.getElementById 来获取到 iframe,随后通过 iframeEl.contentWindow 来发布事件,如下:

let iframeEl: any = document.getElementById(iframeId)if (iframeEl && iframeEl.contentWindow) { iframeEl.contentWindow.mooa.option = window.mooa.option iframeEl.contentWindow.dispatchEvent( new CustomEvent(MOOA_EVENT.ROUTING_CHANGE, { detail: eventArgs }) )}

这样,子应用就不需要修改代码,就可以直接接收对应的事件响应。

监听子应用事件

由于,我们也希望能直接在主工程中处理子程序的事件,并且不修改原有的代码。因此,我们也使用同样的方式来在子应用中监听主应用的事件:

iframeEl.contentWindow.addEventListener(MOOA_EVENT.ROUTING_NAVIGATE, function(event: CustomEvent) { if (event.detail) { navigateAppByName(event.detail) }})

示例

同样的我们仍以 Mooa 框架作为示例,我们只需要在创建 mooa 实例时,配置使用 iframe 模式即可:

this.mooa = new Mooa({ mode: 'iframe', debug: false, parentElement: 'app-home', urlPrefix: 'app', switchMode: 'coexist', preload: true, includeZone: true});...that.mooa.registerApplicationByLink('help', '/assets/help', mooaRouter.matchRoute('help'));that.mooa.registerApplicationByLink('app1', '/assets/app1', mooaRouter.matchRoute('app1'));this.mooa.start();...this.router.events.subscribe((event: any) => { if (event instanceof NavigationEnd) { that.mooa.reRouter(event); }});

子程序则直接使用:https://github.com/phodal/mooa-boilerplate 就可以了。

GitHub 地址:https://github.com/phodal/mooa

原文发布于微信公众号 - phodal(phodal-weixin)

原文发表时间:2018-04-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

编辑于

phodal

145 篇文章57 人订阅

相关文章

来自专栏互联网技术栈

Redis 队列

举例: 队列主要用在系统解耦、流量削峰、异步处理、数据顺序处理等场景。新手在使用时可能会犯一些常见的错误。下面讲一个新手容易犯的错误,在这个示例中把队列的入...

4235
来自专栏along的开发之旅

windows下安装调教ubuntu 17.10步骤

安装ubuntu好多次了, 每次安装都有一些重复步骤要走, 但是这些步骤又比较细, 不用的时间一长就忘记了, 所以在这里单独记录一下, 省的每次都要google...

762
来自专栏漫漫全栈路

Nginx配置文件nginx.conf详解

最近折腾Ubuntu比较多,也基本原理了Windows和IIS了,论一个软狗的堕落史。既然换到Ubuntu系统上来,勉强算个web开发人员的我当然用的最多的就...

6577
来自专栏wblearn

package.json文件快速入门详解

相信入门nodejs或者npm的同学会对package.json这个文件有疑惑,对这个文件的作用不是很清晰,但搭建自己的博客每每用到node,npm这个文件又必...

1381
来自专栏blackheart的专栏

[OIDC in Action] 1. 基于OIDC(OpenID Connect)的SSO

在[认证授权]系列博客中,分别对OAuth2和OIDC在理论概念方面进行了解释说明,其间虽然我有写过一个完整的示例(https://github.com/lin...

37210
来自专栏24K纯开源

Windows下程序打包发布时的小技巧

一、背景     Windows下开发的应用程序在发布时,需要将其依赖的一些动态链接库一起打进安装包里面去。这个时候,快速确定这个程序到底依赖哪些动态链接库变得...

2646
来自专栏云计算教程系列

开源资产管理系统Snipe-IT安装教程

在IT行业中,需要完整的生命周期跟踪资产的资产管理,包括采购,维护,存储和处置。Snipe-IT是专为IT资产管理而设计的免费开源应用程序,提供基于Web的界面...

1.5K4
来自专栏京东技术

必须掌握的ADB命令 | 让你的测试事半功倍

ADB的全称是Android Debug Bridge,是一个与模拟器或者连接设备通讯的桥梁。ADB是CS结构包含三个部分:

1.4K4
来自专栏Java后端技术

GitLab配置ssh key

  当前很多公司都选择git作为代码版本控制工具,然后自己公司搭建私有的gitlab来管理代码,我们在clone代码的时候可以选择http协议,当然我们亦可以选...

1133
来自专栏happyJared

Java开发人员常用的服务配置(Nginx、Tomcat、JVM、Mysql、Redis)

4041

扫码关注云+社区

领取腾讯云代金券