Reputation: 71
I am integrating breezeJS into an existing requireJS project which already uses knockoutJS. I ran into a couple of problems.
The first was that breeze is unable to load the Q library unless i include it on my html wrapper as a <script>
tag, not as a loaded AMD dependency. In my project i am trying to keep my code down to a single script tag, so this isnt ideal.
The second issue is that breezeJS is unable to load knockout. In my main.js I have defined a path for knockout to be:
knockout: '../libs/knockout/knockout-2.2.0',
(I do this because I like knowing for sure that I am not accessing a global ko
)
However when i added breeze to my project, breeze wasn't able to load my knockout library. Looking into the breeze code i can see that it has been hardcoded to load the knockout library as ko
.
Not wanting to change all of my code i found that i could add my AMD loaded knockout library to the global window object as window['ko']
. But this feels like quite a bodge. Also weirdly adding Q this way and removing the <script>
tag didn't work, as i think Q is required too early in the application's lifecycle, even before i get to pollute the global - i did nest my require()
calls in main.js but that hid the majority of my application files from the build process so i abandoned that approach.
How can i include Q and knockout and breeze in my project and still use a single line <script>
tag, at the moment I am having to include Q as a separate <script>
tag and pollute the global to get breeze and knockout to play nicely.
I am using quite a few other libraries in my project and none of them have been this difficult to integrate in.
Any help is much appreciated
Cheers
Gav
EDIT: Here is my full require config:
require.config({
/**
* shims are for 3rd party libraries that have not been written in AMD format.
* shims define AMD modules definitions that get created at runtime.
*/
shim: {
'jqueryUI': { deps: ['jquery'] },
'jqueryAnimateEnhanced': { deps: ['jqueryUI'] },
'jqueryScrollTo': { deps: ['jquery'] },
'touchPunch': { deps: ['jquery'] },
//'Q': { exports: 'Q' },
//'breeze': { deps: ['Q', 'knockout'], exports: 'breeze' },
'path': { exports: 'Path' },
//'signalR': { deps: ['jquery'] },
},
paths: {
//jquery
jquery: '../libs/jquery/jquery-1.7.2.min',
'jquery.adapter': '../libs/jquery/jquery.adapter',
//jquery plugins
horizontalNav: '../libs/jquery/plugins/horizontalNav/jquery.horizontalNav',
jqueryUI: '../libs/jquery/plugins/jquery-ui/jquery-ui-1.9.2.custom',
jqueryAnimateEnhanced: '../libs/jquery/plugins/animate-enhanced/jquery.animate-enhanced',
touchPunch: '../libs/jquery/plugins/touch-punch/jquery.ui.touch-punch.min',
//jqueryScrollTo: '../libs/jquery/plugins/jquery-scrollTo/jquery.scrollTo.min',
//reveal: '../libs/jquery/plugins/reveal/jquery.reveal',
//opentip: '../libs/jquery/plugins/opentip/opentip-jquery',
//RequireJS
domReady: '../libs/require/plugins/domReady',
text: '../libs/require/plugins/text',
async: '../libs/require/plugins/async',
depend: '../libs/require/plugins/depend',
json: '../libs/require/plugins/json',
noext: '../libs/require/plugins/noext',
//coffee-script
'coffee-script': '../libs/coffee/coffee-script',
cs: '../libs/require/plugins/cs',
//Path
path: '../libs/path/path.min',
//Knockout
knockout: '../libs/knockout/knockout-2.2.0',
knockoutTemplateSource: '../libs/knockout/ko.templateSource',
knockoutValidation: '../libs/knockout/ko.validation',
//breeze
Q: '../libs/breeze/q',
breeze: '../libs/breeze/breeze.debug',
//Signals (Observer pattern)
signals: '../libs/signals/signals',
//SignalR - Push notifications
signalR: '../libs/signalR/jquery.signalR-0.5.2.min',
//utils
logger: 'common/logging/logger',
tinycolor: '../libs/tinycolor/tinycolor',
composing: 'common/composition/composing',
//app specific
BaseWidgetViewModel: 'app/view/core/BaseWidgetViewModel',
}
});
Upvotes: 7
Views: 1957
Reputation: 17052
This should be fixed as of Breeze v 1.2.4. We no longer use an internal implementation of "require".
Upvotes: 2
Reputation: 17863
Sorry for the (holiday) delay in addressing your question.
I understand and appreciate your goal of eliminating every script tag except the one for RequireJS. This goal is not easily obtained in my experience.
You did uncover a Breeze defect. Breeze internally is referencing a different 'require' function than your application's 'require' function. It doesn't know about the application 'require' function or its configuration. Therefore, when you omit the Q script tag, Breeze cannot find Q ... no matter how well you configure the application 'require'.
We'll have to fix that. I'll add a comment here when we do.
Meanwhile you'll must use a script tag for 'Q' and for 'KO' and you must put those tags above the script tag for RequireJs. Please continue to use require for your application scripts.
Unfortunately, you have other problems that are unrelated to the dual-require-function problem.
First, I think you will always have trouble keeping KO out of the global namespace ... and this has nothing to do with Breeze.
In KO's AMD implementation (at least when I last looked), KO is either in the global namespace or in the require container; never both. Unfortunately, many useful plug-ins (bindingHandlers, debug.helpers) assume it is in the global namespace; you won't be able to use them if you load KO with require.
You can load Knockout in script tags before Require and then shim KO into the Require container during configuration. Your configuration might look like this:
define('knockout', [], function () { return window.ko; });
The jQuery developers realized this would be a problem. Too many good plugins assume jQuery is in the global namespace. Rather than be purists, the jQuery maintainers (correctly in my view) put jQuery in both the Require container and in the global namespace.
Second, many other useful libraries do not support Require. Your code can be written as if these scripts were designed for require. I still think the easiest, clearest way to handle this is specify them in script tags. Then you can add them into the container by defining them with define
calls as shown above. With this shimming, your own modules can be consistent in relying on Require for service location and dependency injection of these libraries.
Third, I think you have a bug in your configuration. For reasons that escape me, you decided to refer to the Knockout module as "knockout" in your Require universe.
Fine ... but you shouldn't expect Breeze to anticipate that module name when we fix it to use the application's require container. Breeze will be looking for KnockoutJs under its standard name, "ko". Breeze will not find it under your preferred name, "knockout".
This is not a big deal. If you're wedded to the "knockout" name, you can make the same instance available under both names. I'm pretty sure the following shim line will work when added to your configuration code:
define('ko', ['knockout'], function (ko) { return ko; });
Again ... this will be effective only after we fix our Breeze require bug.
John Papa had to address many similar issues in Code Camper; you might look at what he did there, especially at main.js
.
Upvotes: 3
Reputation: 552
Sounds like your require config is not right. Could you post the code of your require config? I am curious:
keep my code down to a single script tag
why that?
Edit: Now i get it. Still sounds like the require config is wrong.
Upvotes: 0