您正在研究的大多数(全部?)框架都解决了相同的问题,但它们以略有不同的方式来解决问题,目标也略有不同。
我认为可以公平地说,所有这些项目都会解决这些类别的问题:
- 提供一组合理的默认值
- 减少样板代码
- 在 BackboneJS 构建块之上提供应用程序结构
- 提取作者在其应用程序中使用的模式
我从 2011 年 12 月开始制作的 Marionette 也有一些非常明确的目标和理想:
- 复合应用架构
- 企业消息传递模式影响
- 模块化选项
- 增量使用(没有全有或全无要求)
- 没有服务器锁定
- 轻松更改这些默认值
- 代码作为配置/过度配置
我并不是说其他框架都没有这些相同的目标。但我认为 Marionette 的独特性来自于这些目标的结合。
复合应用架构
我在使用 WinForms 和 C# 的胖客户端分布式软件系统中工作了 5 年多。我为台式机、笔记本电脑(智能客户端)、移动设备和 Web 应用程序构建了应用程序,它们都共享一个核心功能集并多次使用相同的服务器后端。在这段时间里,我了解了模块化的价值,并很快走上了复合应用程序设计的道路。
基本思想是“组合”应用程序的运行时体验并处理许多较小的、不一定相互了解的单独部分。它们向整个复合应用系统注册自己,然后通过各种解耦消息和调用的方式进行通信。
我在我的博客上写过一些关于这个的文章,介绍 Marionette 作为 Backbone 的复合应用程序架构:
消息队列/模式
同样大规模的分布式系统还利用消息队列、企业集成模式(消息传递模式)和服务总线来处理消息。最重要的是,这对我的解耦软件开发方法产生了巨大影响。我开始从这个角度看待单进程、内存中的 WinForms 应用程序,很快我的服务器端和 Web 应用程序开发也受此影响。
这直接转化为我对 Backbone 应用程序设计的看法。我在 Marionette 中为高级应用程序对象和您在应用程序中创建的每个模块提供了一个事件聚合器。
我考虑可以在我的模块之间发送的消息:命令消息、事件消息等等。我还将服务器端通信视为具有这些相同模式的消息。有些模式已经进入 Marionette,但有些还没有。
模块化
代码的模块化非常重要。对于任何具有显着规模和复杂性的系统,都必须创建具有明确定义的入口和出口点的小型、封装良好的封装。
Marionette 通过其module
定义直接提供模块化。但我也认识到有些人喜欢 RequireJS 并想使用它。所以我提供了标准构建和 RequireJS 兼容构建。
MyApp = new Backbone.Marionette.Application();
MyApp.module("MyModule", function(MyModule, MyApp, Backbone, Marionette, $, _){
// your module code goes here
});
(目前还没有可用的博客文章)
增量使用
这是我在 Marionette 的每一个部分中我能做到的核心理念之一:对 Marionette 的使用没有“全有或全无”的要求。
Backbone 本身对所有的构建块对象都采用了一种非常增量和模块化的方法。您可以自由选择要使用的那些,何时使用。我坚信这一原则,并努力确保 Marionette 以同样的方式工作。
为此,我为 Marionette 构建的大部分部件都是独立构建的,可以与 Backbone 的核心部件一起使用,并且可以更好地协同工作。
例如,几乎每个 Backbone 应用程序都需要在屏幕上的特定位置动态显示 Backbone 视图。这些应用程序还需要在新视图到位时处理关闭旧视图并清理内存。这就是 Marionette'sRegion
发挥作用的地方。区域处理获取视图、在其上调用渲染以及将结果填充到 DOM 中的样板代码。然后将关闭该视图并为您清理它,前提是您的视图上有一个“关闭”方法。
MyApp.addRegions({
someRegion: "#some-div"
});
MyApp.someRegion.show(new MyView());
但是您不需要使用 Marionette 的视图来使用区域。唯一的要求是您在对象原型链中的某个点从 Backbone.View 扩展。如果您选择提供close
方法、onShow
方法或其他方式,木偶区会在合适的时间为您调用。
无服务器锁定
我在各种服务器技术之上构建 Backbone / Marionette 应用程序:
- ASP.NET MVC
- Ruby on Rails
- 红宝石/西纳特拉
- NodeJS / ExpressJS
- PHP / 苗条
- 爪哇
- 二郎
- ... 和更多
当涉及在浏览器中运行时,JavaScript 就是 JavaScript。服务器端 JavaScript 也很棒,但它对我如何编写基于浏览器的 JavaScript 的影响或影响为零。
由于我构建的项目和客户使用的后端技术的多样性,我不能也不会出于任何原因将 Marionette 锁定在单个服务器端技术堆栈中。我不会提供样板项目。我不会提供 ruby gem 或 npm 包。我希望人们了解 Marionette 不需要特定的后端服务器。它是基于浏览器的 JavaScript,后端无关紧要。
当然,我完全支持其他人为他们的语言和框架提供包。我在 Wiki 中列出了这些包,并希望人们在看到需要时继续构建更多包。但这是社区支持,而不是 Marionette 的直接支持。
轻松更改默认值
为了减少样板代码并提供合理的默认值(这是我直接从 Tim Branyen 的 LayoutManager 中“借用”的一个想法),我认识到其他开发人员需要使用与我略有不同的实现。
我提供基于<script>
模板内联标签的渲染,默认使用 Underscore.js 模板。但是您可以通过更改Marionette 中的Renderer
和/或对象来替换它。TempalteCache
这两个对象提供了渲染功能的核心,并且有一些 wiki 页面展示了如何针对特定的模板引擎和加载模板的不同方式进行更改。
使用 Marionette v0.9,它变得更加容易。例如,如果你想用预编译的模板替换内联模板脚本块的使用,你只需要替换 Renderer 上的一种方法:
Backbone.Marionette.Renderer.render = function(template, data){
return template(data);
};
template
现在整个应用程序将使用您附加到视图属性的预编译模板。
我什至在 v0.9 中提供了一个 Marionette.Async 附加组件,它允许您支持异步呈现视图。我一直在努力尽可能简单地替换 Marionette 中的默认行为。
代码作为配置
在某些情况下,我是“约定优于配置”的粉丝。这是完成工作的一种强有力的方式,而 Marionette 提供了一些这样的方法——虽然不是太多,老实说。许多其他框架 - 尤其是 LayoutManager - 提供了比 Marionette 更多的配置约定。
这是有目的和意图的。
我已经构建了足够多的 JavaScript 插件、框架、附加组件和应用程序,以了解尝试让约定以有意义且快速的方式工作的痛苦。它可以快速完成,但通常以能够改变它为代价。
为此,我对 Marionette 采用了“代码即配置”的方法。我没有提供很多“配置”API,您可以在其中提供具有静态值的对象文字,这些值会改变一系列行为。相反,我通过带注释的源代码和实际的 API 文档记录了每个对象具有的方法,目的是告诉您如何更改 Marionette 以按照您想要的方式工作。
通过为 Marionette 对象提供简洁明了的 API,我创造了一种情况,即替换特定对象或整个 Marionette 的行为相对简单且非常灵活。我牺牲了“简单”的配置 API 调用来提供您自己的代码以使事情以您想要的方式工作的灵活性。
您不会在 Marionette 中找到“配置”或“选项”API。但是你会发现大量的方法,每一个都服务于一个非常特定的目的,带有清晰的签名,可以很容易地改变 Marionette 的工作方式。