无法加载需要配置路径和 shim 的 Handlebars

Can't load Handlebars with require config path and shim

我已经用 bower 加载了 handlebars,因此它位于 vendor 目录中。似乎我已经将所有内容配置到可以在检查器中看到 handlebars.js 文件已加载的地步,它没有给出 404.. 但据我所知,以下内容应该将其附加到全局命名空间(window)。如您所见,我有我的模块 "loaded" 并且工作正常,但在该模块内部它取决于车把 - 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"]);

这是已加载模块的片段(非 AMD,使用 shim 配置加载):

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);

            // ...
        }
    }
})();

如前所述,我可以在检查器中看到 Handlebars 不是全局命名空间 (window) 的 属性。从我读过的其他帖子中,我看不出我配置错了什么。另外,由于需要加载,我不确定把手有什么问题。

更新

新 main.js 因为车把版本不需要它,看起来:

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"]);

您不需要(也不应该)shim handlebars,因为库集成了一个 UMD wrapper and thus, is compatible with the AMD pattern(其中 requirejs 是一个实现):

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();

实际上,因为当库加载时它会找到 define 函数,它不会将 Handlebars 附加到根对象(即 window)。 结果,很明显,你的 shim 找不到它。

现在您的问题是您想将 Handlebars(一个 AMD 加载的模块)与一个非 AMD 模块一起使用。不幸的是,这不受官方支持:

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.

没有好的解决办法。这里有一些想法:

(1) 我仍然设法通过创建一个 globalHandlebars 模块使其工作:

define(["handlebars"], function(Handlebars){
    window.Handlebars = Handlebars;
});

但这很老套,没有得到官方支持。实际上,似乎不能保证在加载非 AMD 脚本之前会调用 dep 的 define。虽然我的笔记本电脑上从未发生过...

(2) 另一种方法是将 handlebars 作为脚本包含在 html 文件中 before requirejs(因此 define 尚未定义)。 仍然非常 hacky,如果您还使用带 requirejs 的车把,它将加载两次...

(3) 显然,最好的办法是将 loaded 脚本包装在 define 调用中,但我想这可能是不可能的.

(4) 如果您使用优化器,还有一个 wrapShim 选项,但它并不总是有效,具体取决于您的 shimmed 代码的内容。

我没有任何其他解决方案,但 requirejs 人可能有一个。我很惊讶在你之前没有人偶然发现这个问题。

您也可以考虑切换到 browserify or webpack instead of requirejs (webpack natively supports AMD modules and there is an AMD loader for browserify)。 此外,它们都使您能够预先构建模板(使用 this loader for webpack or this transform for browserify)并避免包含整个 handlebars 库,这始终是一个好习惯。