I've loaded handlebars with bower so it resides in a vendor directory. It seems I've configured everything to the point where I can see in inspector that the handlebars.js file is loaded, it doesn't give a 404.. but as far as I know the following should affix it to the global namespace (window). As you can see I have my module "loaded" and that works correct, but inside that module it depends upon handlebars - ReferenceError: Handlebars is not defined
requirejs.config({
baseUrl: "/scripts",
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
"jquery": "vendor/jquery/dist/jquery",
"loaded": "vendor/loaded/dist/loaded",
"handlebars": "vendor/handlebars/handlebars"
},
shim: {
"loaded": {
deps: ["jquery", "handlebars"],
exports: "loaded"
},
"handlebars": {
exports: "Handlebars"
}
}
});
requirejs(["app"]);
Here is a snippet of the loaded module (non-AMD, loads with shim config):
if(typeof loaded === "undefined") loaded = {};
loaded.dispatch = (function() {
// ...
return {
render: function () {
// ...
// gets this far, but error as the library is missing
var template = Handlebars.compile(_template);
// ...
}
}
})();
As mentioned, I can see in the inspector that Handlebars is NOT a property of the global namespace (window). From other posts I've read, I can't see what I've configured wrong. Also, as loaded is being required, I'm not sure what the issue is with handlebars.
UPDATE
New main.js as handlebars version doesn't require it, it would seem:
requirejs.config({
baseUrl: "/scripts",
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
"jquery": "vendor/jquery/dist/jquery",
"loaded": "vendor/loaded/dist/loaded",
"handlebars": "vendor/handlebars/handlebars"
},
shim: {
"loaded": {
deps: ["jquery", "handlebars"],
exports: "loaded"
}
}
});
requirejs(["app"]);
You do not need (and should not) shim handlebars
as the library integrates a UMD wrapper and thus, is compatible with the AMD pattern (of which requirejs
is an implementation):
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Handlebars"] = factory();
else
root["Handlebars"] = factory();
And actually, because when the library will load it will find the define
function, it won't append Handlebars
to the root object (which is window
).
As a result, obviously, your shim can't find it.
Now your problem is that you want to use Handlebars, an AMD loaded module, with a non AMD module. Unfortunately, this is not officially supported:
Only use other "shim" modules as dependencies for shimmed scripts, or AMD libraries that have no dependencies and call define() after they also create a global (like jQuery or lodash). Otherwise, if you use an AMD module as a dependency for a shim config module, after a build, that AMD module may not be evaluated until after the shimmed code in the build executes, and an error will occur. The ultimate fix is to upgrade all the shimmed code to have optional AMD define() calls.
There is no good solutions. Here are some ideas:
(1) I still managed to make it works by creating a globalHandlebars
module with:
define(["handlebars"], function(Handlebars){
window.Handlebars = Handlebars;
});
But this is very hacky and not officially supported. Indeed, it seems that you are not guaranteed that the dep's define
will be called before your non AMD script is loaded. Never happened on my laptop though...
(2) Another way to make it works is to include handlebars
as a script in your html file before requirejs
(so that define
is not yet defined).
Still very hacky and if you also use handlebars with requirejs
, it will be loaded twice...
(3) Obviously the best would be if you could wrap your loaded
script in a define
call but I guess it may not be possible.
(4) If you use the optimiser, there is also a wrapShim
option though it does not always work depending on the content of your shimmed code.
I don't have any other solutions but maybe the requirejs
people have one. I am surprised nobody stumbled on this issue before you.
You may also consider switching to browserify or webpack instead of requirejs (webpack natively supports AMD modules and there is an AMD loader for browserify).
Additionally, both of them enables you to pre-build your templates (using this loader for webpack or this transform for browserify) and avoid including the whole handlebars
library which is always a good practice.