单SPA – 范围示例
该项目的目的是提供一个示例,说明如何构建由多个单页应用程序(SPA)组成的门户网站。每个水疗中心都应通过自己的构建过程自我包含。如果任何单个应用程序都有更改,则应单独部署无需部署整个应用程序。
此示例基于简单的spa-spa-webpack-example,但将提供其他功能,例如:
- 将水疗中心与自己的构建过程隔离
- 加载水疗中心的SystemJS的需求
- 提供一种在每个水疗中心之间进行交流的方法
- 获取来自不同服务器的资产(例如图像,字体,CSS等)工作
- 支持多个没有区域的角版。JS冲突。有关详细信息,请参见多个角应用
- 支持Angular AOT构建
如何运行这个项目
- 克隆这个项目
- 跳入每个应用程序文件夹并执行:
-
npm install -
npm run watch:portal
-
- 然后以:
-
npm install -
npm run watch
-
- 打开http:// localhost:9000在Web浏览器中。
NPM任务
watch:portal :将应用程序构建为UMD模块,将单身人士作为中间件构建,以通过门户使用该应用程序。更改将自动检测到。
build:portal :将应用程序作为UMD模块发布,并将所有内容输出到文件夹中。您可以将生产中的生产文件上传到网络服务器。提示:Ant Angular 6示例正在使用AOT构建。您可以使用npm run build:portal -- --env.analyzeBundle以查看捆绑包内没有编译器。
watch:standalone :如果您只想在没有整个门户网站的情况下开发单个应用程序,则可以使用此任务。检查控制台日志以查看该应用程序正在提供的端口。此任务是可选的!目前,此任务仅存在于VUE项目中,以作为一个例子。
build:standalone :与watch:standlone taks,这将应用程序构建为独立版本(无需门户)。此任务是可选的!目前,此任务仅存在于VUE项目中,以作为一个例子。
应用间通信
该主题已多次讨论(即在这里或这里)。解决这个问题可能有很多解决方案。在此存储库中,我希望您显示满足以下要求的解决方案:
- 每个应用程序都是一个自包装的系统。没有应用知道另一个应用程序或其数据模型的内部状态。简而言之,每个应用程序都被视为黑匣子,可以由另一个团队维护。
- 每个应用程序必须能够具有复杂的状态。
- 当您在应用程序之间导航时,不得丢失状态(由于安装/卸载)。
为了满足这些要求,我决定了每个应用程序可以或无法收听其他应用程序发送的事件的事件系统。这使每个应用程序能够根据其他应用程序的事件(可能会重新启动其他事件)来保持其孤立状态并仅修改自己的状态。没有应用需要直接访问另一个应用程序的状态。
此外,我需要将应用程序分为两个部分。一个是普通应用本身(GUI,框架等),另一个是“通信层”,该“通信层”被导出为单独的模块并由门户进行加载/实例化,而不管应用程序状态如何。这使每个应用程序都可以聆听并反应事件,即使它们没有安装。
每个应用程序都可以以任何喜欢的方式处理这些事件。唯一的要求是,所有应用程序都同意一种事件格式,以发送和接收这些事件。
在此示例中,我决定只使用Redux,因为它基本上是我需要的。投掷事件和过程事件。但是该系统与您喜欢的任何技术一起使用。
这是一个图形,说明了实际发生的事情:
主要部分是:
StoreApps:包含状态 +业务逻辑。如果发生全球事件,则实现GlobaleventDistributor可以调用的调度方法。
Guiapps: Singlespa中间件 + UI代码(例如HTML,CSS,Controller等)。
GlobaleventDistributor:可用于注册商店。向所有商店发送调度事件。 (观察者模式)
它的工作原理:
- 根式启动启动并加载所有存储并实例化。这是必要的,因为我们需要始终保持通信层(商店)。即使整个应用程序尚未安装。否则,不会处理特定的应用程序。
- 安装应用程序时,根应用将通过属于单个应用程序的已经实例化的商店。根应用还将对GlobaleVentDistributor的引用传递给该应用。
- 现在,您可以将所有全球事件愉快地发送给GlobaleventDistributor,并使用dispatch()方法和所有其他活动发送给本地商店。
缺点:
如前所述,最大的缺点是,在扎根加载时,必须加载所有商店。这样做的原因是,我们正在建立一个项目,该项目将完全在浏览器中具有巨大的应用状态。用户可能会在没有任何服务器通信的情况下输入1H数据,一旦完成,他将单击一键保存所有内容。这不一定是您的用例。例如,如果您只对任何当前活动应用程序感兴趣,则可能不需要事先加载所有状态,而是在应用程序安装时加载它们。
多个角度应用
Angular 2+的最大问题是,它(或Angular依赖于Angular依赖的第三方库)污染了全局窗口对象。一个这样的图书馆就是Zone.J。 Zone.js Monkey修补所有异步事件,并将其引用添加到窗口对象。如果您运行了多个Angular应用程序,Angular将抱怨该区域已加载。
一种可能的解决方案是将Zone.js与所有角应用和负载区域分开。这可能不是最好的解决方案,因为一旦您拥有多个不同的角版本与门户网站中的应用程序,则可能有些人可能需要不同的区域。JS版本。这可能会破坏这一点。即使这不是一个很好的解决方案,它也可能是我们目前的角度状态的最佳解决方案。
我发现的另一个解决方案是用自己的iframe加载每个角应用程序。这样做,每个角应用程序都完全隔离。然后,您可以将Angular的渲染目标设置为父窗口。使用该解决方案,Angular在完整的隔离上下文中运行,但将所有内容呈现到主DOM。可悲的是,这也不是完美的解决方案,因为您打开了许多其他要处理的其他问题。一些例子是:
- 您需要手动将所有CSS样式从iframe放到父窗口
- Angular路由器无法再访问浏览器URL以根据应用程序路由进行更新
- 您不能使用依赖文档事件的第三方UI库。 (即一个下拉组件,想知道何时单击文档以关闭文档。)
将来,我们可能会有更好的解决方案(例如Angular Elements)来处理此问题,直到那时,我们最好的选择是将一个Zone.js实例放入门户网站应用程序。这正是我在这个示例项目中所做的。
叉子
- https://githu*b.*c*om/tsukhu/single-pa-portal-monorepo(如果您打算使用同一团队维护的多个应用程序的monorepo,您可能会对此叉子感兴趣,该叉子可以集成Yarn Workspaces + Lerna,以简化开发过程。
