问题
My library use kriskowal/Q promises library and now I'm trying to load (with requirejs) application that use my library so I put all paths and shims and my requirejs.config
section looks like this:
requirejs.config({
baseUrl: './',
catchError: false,
paths: {
beril: '../engine/build/src/bundle',
lodash: 'bower_components/lodash/lodash',
three: 'bower_components/three.js/build/three',
q: 'bower_components/q/q',
},
shim: {
lodash: {
exports: '_'
},
three: {
exports: 'THREE'
},
q: {
exports: 'Q'
},
beril: {
deps: ['lodash', 'three', 'q'],
exports: 'beril'
},
}
});
After this I suppose variables THREE, _ and Q to be defined in global space. Now I'm loading and runinng application with this simple line:
require(['beril', 'js/stepbystep/' + $stateParams.page + '/app'], (beril, app) => app());
but then I'm getting error: ReferenceError: Q is not defined
even though I can see in Chrome's network inspector that Q library have been loaded.
Also all the rest dependencies (THREE and _) are defined. Seems like requirejs`s shim does not work for this library. Can it be or am I missing something?
So what am I'm doing wrong and how should I deal with this situation?
回答1:
I found solution and it was to add init
function to my library's shim and then add Q
as global object manually so my shim section now looks like this:
shim: {
lodash: {
exports: '_'
},
three: {
exports: 'THREE'
},
q: {
exports: 'Q'
},
beril: {
deps: ['lodash', 'three', 'q'],
exports: 'beril',
init: function(lodash, three, q){
window.Q = q;
}
},
}
however I don't clearly understand why it does not work without this and are there better ways to deal with this situation.
回答2:
There are a few problems with your configuration. For one thing, you have unnecessary shim
configurations. I installed lodash just now (with bower install lodash
) and searched its code. It calls define
. So you must not set a shim
for it. RequireJS won't give you an error but you will get undefined behavior. The same is true of Q: it calls define
so, no shim
for it. Last I checked, THREE
needs a shim
.
The fact that Q calls define
is also why it does not leak the symbol Q
into the global space. It acts like a well-behaved AMD-module.
Ok, so how can we get Beril to find Q? Your solution works but I find it slightly iffy. The problem is that init
is executed after the shimmed module is loaded. As long as Beril refers to Q
only in the body of functions to be executed later, it will work. And I guess this is how Beril works now. However, if a new version of Beril needs to refer to Q
when the file that contains Beril is first executed, it will fail because Q
does not exist yet.
One way to work around the problem that is future-proof is to use map
and some glue. Keep your shim
for beril
but remove the init
. Define a module named q-glue
:
define(['q'], function (Q) {
window.Q = Q;
return Q;
});
And declare this map in your configuration:
map: {
beril: {
q: "q-glue"
}
}
This says "when q
is requested from beril
load q-glue
instead." By doing this, window.Q
will be defined before Beril is loaded.
I take it you are the author of Beril. I urge you to make your library AMD-compatible so as to spare users of your library having to go through configuration pains to get it working with AMD-loaders (like RequireJS).
回答3:
It worked for me after I downgraded to version 0.9 up until 1.0.1 as mentioned in the readme. The current version 2.0.2 has significant braking changes as mentioned by Kris Kowal here.
I didn't have the need to set the global variable as the older version checks the environment and does so if loaded before require.
回答4:
You need to add q
to require()
...
require(['beril', 'q', 'js/stepbystep/' + $stateParams.page + '/app'], (app, beril, q) => app());
来源:https://stackoverflow.com/questions/35163145/how-to-load-q-library-with-require-js