在我的旅途中,我发现Breeze可以使用Breeze模型的多个库,例如Backbone,Knockout,Angular和其他框架。当Breeze作为Require模块加载时,Breeze会检查是否存在Knockout模块,别名为“ko”。此模块名称与Durandal别名Knockout的方式相冲突,因为Durandal使用模块名称“knockout”代替。
当Breeze加载时,会进行检查以确定如何呈现Breeze模型的数据属性。在我的原始项目中,Breeze将检测全局范围内的Knockout并分配所有属性“ko.observable()”样式属性。
如何才能让这些模块正常播放?我尝试了几种Require.JS技巧,比如添加这个Shim:(from this post)
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 observable。相反,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属性,而不是淘汰属性)
答案 0 :(得分:7)
看起来您正在尝试通过 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” 。这意味着当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属性。
您可以稍后在启动过程中更改该选择,可能在您首先与Breeze交互的dataservice
或datacontext
模块中创建EntityManager
。
在您进行第一次Breeze互动之前,请致电
breeze.config.initializeAdapterInstance("modelLibrary", "ko", true);
这将Knockout建立为Breeze在创建/实现实体时应使用的模型库。此后,将使用KO可观察属性创建实体。
将
不要希望Breeze等到 requireJS 异步加载'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 ,但你现在必须使用可观察的函数属性。 我们希望通过v.2.1 希望这些想法和变化能让你走上成功的道路。 Durandal 2.0
总之