问题
I am trying to run a widget on a web page that leverages the Q library. Unfortunately, the page also uses the AddThis widget which embeds require.js and is causing a conflict. Specifically, when run together the two following error messages are displayed in the console:
Uncaught ReferenceError: Q is not defined
Uncaught Error: Mismatched anonymous define() module
Unfortunately, I don't have control over the use of the AddThis widget. However, I do have control over the embedded application using Q. Is there a JavaScript pattern that I can implement to namespace the Q library so that it will not conflict with require.js?
Here is a simple example that demonstrates the problem:
<!doctype html />
<html>
<head>
<script src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.1.15/require.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/q.js/0.9.2/q.min.js"></script>
</head>
<body>
<script>
var called = function() {
var deferred = Q.defer();
console.log("Q called successfully");
deferred.resolve();
return deferred.promise;
}
Q.fcall(called);
</script>
</body>
</html>
回答1:
I'll preface this by saying I'm not familiar with "AddThis", and wouldn't call myself an expert on Require, but I'll try to work through the layers of problems you've got in this situation.
First, when Q finds require, it doesn't put itself in the global namespace, but just calls define
with the Q module. This creates an anonymous module within require which is loaded by calling require
using the path of that file. This is a common pattern for modules that might be used in non-browser environments. When you comment out that block, it goes down to the "script" module loader, where it creates an instance of the Q module and sets it on self
. In the browser, this is (apparently) aliased to window.
So, how do we solve this problem without commenting out parts of the module junk in q.js?
You SHOULD be able to use Require's shim configuration to export Q to the global scope, which would look like this:
require.config({
shim: {
Q: {
exports: "Q"
}
}
});
But there's 2 problems with this. Firstly, you're not in control of the require config, right? It's loaded by the "AddThis" plugin. Secondly, exporting Q from a shim config doesn't even seem to work for Q, possibly because Q uses "define" internally ( Require says that scripts using "define" internally might not be shimmed properly. This might also be what's triggering your "Mismatched anonymous define() module" error ). It's weird that there doesn't seem to be any other SO questions or issues on Q's github about this lack of shim-ability. I'm not sure if Q is doing something "wrong" or I'm just crazy. Maybe someone who knows a little more about module shimming could comment on that.
In any case, you can't shim it here. You should be able to do something like this:
if ( require ){
require(['path/to/Q'],function(Q){ window.Q = Q; });
}
This will explicitly require Q only if require exists and save it to the window variable so you can use it wherever.
However, this also has a problem. The "path/to/Q" here will be relative to any baseUrl set in that require's config. So, if "AddThis" is setting the baseUrl to be some weird path for that plugin where it's hard for you to get at Q, then you might have to solve that problem.
You might be able to use Require's multiversion ability to set your own config where you specify your own baseUrl:
if ( require ){
var myRequire = require.config({
baseUrl: '/my/local/root',
paths: {
Q: 'path/to/Q'
}
});
myRequire(['Q'],function(Q){
window.Q = Q;
bootstrapMyApp();
});
}
else {
bootstrapMyApp();
}
This is completely untested, but it seems like it might work!
来源:https://stackoverflow.com/questions/27116780/running-q-on-page-with-require-js