问题
I am creating a single page app built on AngularJS, Breeze, and RequireJS. In setting up AMD with requirejs to work with Angular and Breeze, I encountered an issue with Breeze's dependency on "q". If the configuration rule for "q" is lowercase, even if there is no explicit export in the "shim", Breeze gives this error:
Uncaught Error: Unable to initialize Q. See https://github.com/kriskowal/q
"http://localhost:1498/Scripts/shared/breeze.js"breeze.js:1`
When require config changes all references from "q" to "Q" (even without the export), the code works. Does anyone know why this is happening?
This is the working require config:
require.config({
baseUrl: '../Scripts',
paths: {
angular: 'shared/angular',
bootstrap: 'shared/ui-bootstrap',
dropdowns: 'app/directives/dropdowns',
employeeApp: 'app/modules/employeeModule',
controllers: 'app/controllers',
dates: 'app/directives/dates',
jquery: 'shared/jquery',
Q: 'shared/q',
breeze: 'shared/breeze',
config: 'app/services/config',
model: 'app/services/model',
dataservice: 'app/services/dataservice',
expenseInfo: 'app/services/expenseInfo'
},
shim: {
'angular': { 'exports': 'angular' },
'bootstrap': { deps: ['angular'] },
//'q': { 'exports': 'q' },
'breeze': { deps: ['Q', 'jquery'], 'exports': 'breeze' }
},
priority: [ 'angular', 'bootstrap', 'dropdowns', 'jquery',
'Q', 'breeze', 'employeeSearch', 'dates' ]
});
回答1:
Technical reason is that breeze explicitly looks for "Q". To find all the breeze requires search for 'requireLib' (not whole word) in the source.
Breeze always looks for global first, and since q's global is 'Q' that's what breeze searches for
More background: (yes I've been experiencing some Breeze + RequireJS pain lately)
Fortunately you can just change the require path. However with knockout + Durandal this does not work. Breeze requires 'ko', but Durandal requires 'knockout'. The workaround is to use RequireJS map:
map: {
//knockout used by Durandal, ko used by breeze --> anytime ko is requested, substitute knockout
'*': { 'ko': 'knockout' }
}
Breeze does have some problems with its RequireJS dependencies, because it does not predefine its dependencies (no dependencies listed in its define call). This is probably because some of its dependencies are configurable (you don't want knockout, but I do). That's why you need the shim to ensure they are loaded before Breeze requests them.
jQuery has unusual AMD behaviour. Most libraries look for AMD libraries when they run. If they find a AMD library (e.g. RequireJS) they load themselves into it (e.g. define( ... )), and skip loading themselves as a global. jQuery does both if it can (for good reasons). This means Breeze always sees and loads the global jQuery, so no need to create a map from Breeze's 'jQuery' to RequireJS's 'jquery'.
BTW "even without the export" is irrelevant. The export property in the shim is used to: Once loaded, use the global 'breeze' as the module value. No point as breeze sees RequireJS, loads itself into it instead of the global, and shim ignores the export.
回答2:
While it is possible to load all modules through requireJs, since my first answer I've discovered a couple of difficulties that made it too troublesome for me.
If your are going to use requireJs optomize (rjs) and almond to deliver a combined js file with almond's cutdown AMD loader, then you will find errors with some libraries. Specifically I encountered problems with Breeze, & Toastr.
The optomizer expects explicit define statements with the dependencies explicitly named. Breeze uses variable dependency names as it loads them as it finds it needs them - as its dependencies are configured at runtime.
The other problem is using CDN files. Almond does not handle any network files, so they must be preloaded. jQuery is the prime CDN candidate, but it is a requirement for many modules including breeze. And optomize shim's can not depend on any CDN file.
My Solution
I fixed Toastr for optomize with my own patch https://github.com/CodeSeven/toastr/issues/135.
But since it was going to be cumbersome to fix Breeze I went back to preloading it via bundling. I also added any libraries I thought would benefit from from being sourced from a CDN.
I loaded breeze (and its prerequisites) and CDN files via ASP.Net bundles Then define them for requireJs prior to requirejs.config in my main.js
To use these predefined preloads in my production code, I configure my weyland-config.js with optomize's empty e.g.
'jquery': 'empty:',
'knockout': 'empty:',
'Q': 'empty:',
'breeze': 'empty:',
HTH
来源:https://stackoverflow.com/questions/18321563/difference-between-q-and-q-in-angularjs-and-requirejs