Durandal.JS和Breeze.JS在一起玩有些麻烦.Durandal基于几个库,其中两个是Require和Knockout.在使用Require引入的模块化模式之前,我的原始项目使用了Breeze模型上的Knockout样式绑定.
在我的旅途中,我发现Breeze可以使用Breeze模型的多个库,例如Backbone,Knockout,Angular和其他框架.当Breeze作为Require模块加载时,Breeze会检查是否存在Knockout模块,别名为"ko".此模块名称与Durandal别名Knockout的方式相冲突,因为Durandal使用模块名称"knockout"代替.
当Breeze加载时,将进行检查以确定如何呈现Breeze模型的数据属性.在我的原始项目中,Breeze将检测全局范围内的Knockout并分配所有属性"ko.observable()"样式属性.
如何才能让这些模块正常播放?我已经尝试了几个Require.JS技巧,比如添加这个Shim :( 来自这篇文章)
breeze: { deps: ['ko', 'jQuery', 'Q'] }
并添加这些虚拟模块定义:
define('ko', ['knockout'], function (ko) { return ko; }); define('Q', ['q'], function (Q) { return Q; }); define('jQuery', ['jquery'], function ($) { return $; });
在我的main.js. 这个组合允许Breeze运行.我能够针对后端API成功执行查询.
但是,结果没有正确地变成Knockout可观察的.相反,Breeze似乎使用本机ES5可观察属性.虽然这实际上有点酷,但它完全打破了我现有的模块.
需要注意的是,正如Druandal文档所建议的那样,我使用他们提供的代码片段来覆盖内部Promise库.
system.defer = function (action) { var deferred = Q.defer(); action.call(deferred, deferred); var promise = deferred.promise; deferred.promise = function () { return promise; }; return deferred; };
这些相同的问题都出现在Q库和jQuery库中,尽管上面的垫片和虚拟模块纠正了这种行为.我不知道下一步该尝试什么.
编辑:响应"显示您的上下文设置"评论:
define([ 'breeze', 'q', 'durandal/system', 'lodash' ], function (breeze, Q, system, _) { return new function () { var self = this; self.create = create; self.init = init; var EntityQuery = breeze.EntityQuery; var BREEZE_URL = '/breeze/AtlasApi/'; var masterManager = new breeze.EntityManager(BREEZE_URL); self.masterManager = masterManager; function init() { return masterManager.fetchMetadata() .fail(function (error) { system.error(error); }); }; function create() { var manager = masterManager.createEmptyCopy(); return manager; }; }; });
上面的模块我在AppStart加载一次并调用Init方法以确保我有元数据.然后我在其他地方调用.create()来创建一个空的,孤立的副本.这在非Require.js环境中非常有效.我使用promises来确保init步骤已经完成.我可以手动运行查询并且它们可以工作,减去Breeze实现实体的方式(再次,作为ES5属性,而不是敲除属性)
看起来你正试图通过requireJS加载每个库.我记得开箱即用的Durandal方法是直接加载第三方脚本(在require之外)并且仅对应用程序脚本使用require.
这简化了事情,但它不是唯一的方法,很多人都想使用require来加载他们的所有脚本.
我们最近(v.1.4.7)更新了" Todo-Require "样本以证明这种方法.我意识到它不是Durandal应用程序,但我希望你能找到你需要的方向.
我将在此复制我认为对您有所帮助的要点.
... <body> <div id="applicationHost"></div> <!-- Require + main. All scripts retrieved async by requireJS --> <script data-main="Scripts/app/main" src="Scripts/require.js"></script> </body> ...
(function () { requirejs.config({ paths: { 'breeze': '../breeze.debug', 'jquery': '../jquery-1.8.3.min', 'ko': '../knockout-2.2.0', 'Q': '../q' } }); // Launch the app // Start by requiring the 3rd party libraries that Breeze should find define(['require', 'ko', 'jquery', 'logger', 'Q'], function (require, ko, $, logger) { logger.info('Breeze Todo is booting'); // require the 'viewModel' shell // require '../text' which is an html-loader require plugin; // see http://requirejs.org/docs/api.html#text require(['viewModel', '../text!view.html'], function (viewModel, viewHtml) { var $view = $(viewHtml); ko.applyBindings(viewModel, $view.get(0)); $("#applicationHost").append($view); }); }); })();
注意我们如何使用路径来定位库并获得按照Breeze期望的那样建立的模块名称.
另请注意,我们强制requireJS在加载Breeze 之前加载这些依赖的第三方库.这非常重要.在Breeze开始寻找它们时,它们必须在requireJS IoC容器中; 如果他们不在那里,Breeze认为他们永远不会在那里.
这就是为什么你看到Breeze将你的实体属性视为ES5属性.该define
在你的电话"背景设置"负荷"KO"和"清风" 在同一时间.这意味着当Breeze在自己的初始化阶段查找时,无法保证会加载'ko'.
如果在Breeze查找时没有加载'ko',Breeze假定您没有使用Knockout并且回退到其原生模型库("backingStore")...它将实体构建为ES5属性.这恰好是Angular应用程序的正确选择.这不是KO应用程序的正确选择.
最后,如果Durandal期望一个模块的名称不同(我会接受你的话),使用requireJS "map"配置来定义同义词,如下例所示:
requirejs.config({ paths: { 'breeze': '../breeze.debug', 'jquery': '../jquery-1.8.3.min', 'ko': '../knockout-2.2.0', 'Q': '../q' }, map: { '*': { 'knockout': 'ko' } } });
现在当Durandal请求'淘汰'时,requireJS会将它映射到(已经加载的)'ko'模块.
这种"地图"技术代替了"虚拟模块"方法,它同样有效:
define('knockout', [ko], function (ko) { return ko; });
在查看示例代码时,您可能想知道此应用程序何时加载Breeze.答案:什么时候viewModel
解决了.它viewModel
有自己的依赖,包括dataservice
它本身依赖于Breeze.依赖注入难道不是很了不起?:-)
您也可以以不同的方式解决问题.
根据您的问题,您可以启动并运行Breeze和Durandal,但Breeze模型库似乎是为Breeze的本机"backingStore"配置的,它将实体属性写为ES5 getter/setter属性.
您可以在以后更改选择在启动过程中,也许dataservice
还是datacontext
模块,你先用微风交互并创建一个EntityManager
.
在您进行第一次Breeze互动之前,请致电
breeze.config.initializeAdapterInstance("modelLibrary", "ko", true);
这将Knockout建立为Breeze在创建/实现实体时应使用的模型库.此后,将使用KO可观察属性创建实体.
这是至关重要的淘汰赛被加载到 requireJS IoC容器和访问为"KO" 之前进行此配置更改,否则微风会抛出异常.
不要指望Breeze等到requireJS异步加载'ko'.适配器初始化是一个同步过程.在Breeze寻找它之前必须加载'ko'.
我被告知Durandal v2.0在某种程度上改变了我在Durandal v.1.x中熟悉的设置模式.我相信我的答案仍然存在密切关系.
我还不熟悉Durandal v.2.我很兴奋,因为它提供了使用ES5属性getter/setter而不是可观察性函数的可能性.我喜欢那一吨!
成本这个特定的功能(这你就没有必须使用)是你必须在ES5兼容的浏览器......这意味着你不能在仍然很受欢迎IE8都跑.ES5属性没有polyfill.
大多数......但不是全部...单页应用程序可以在此限制内运行.
不幸的是,根据Durandal的架构师,在目前的2.0版本中,ES5属性不适用于Breeze.两个图书馆争夺那些吸气者和二传手.因此,您可以将Durandal v2.0与Breeze一起使用,但您现在必须使用可观察的函数属性.
我们希望这个故事能够在第2.1节中得到改进
希望这些想法和变化能让你走上成功的道路.