用 systemjs 替换 requirejs——变量在本地范围内不可见

Replacing requirejs with systemjs -- variables not visible in local scope

我正在尝试将我们的 requirejs 调用转换为使用 SystemJS,但我不确定我做错了什么。

我们原来的调用是这样的:

return function(callback) {
    requirejs(["/app/shared.js"], function(result){
        callbackFunction = callback;
        callback(dashboard);
        main();
    })
}

而我正在尝试的是:

return function(callback) {
    console.log(callback.toString())
    SystemJS.import('app/shared.js').then(function(result){
        callbackFunction = callback;
        callback(dashboard);
        main();
    });
}

我不得不删除一些前导 / 以使内容正确加载,这很好,但我现在 运行 遇到了一个问题,即在顶部定义的变量的 shared.js 在我的本地 main.js 文件中不可见。在我的浏览器控制台中,我得到:

Potentially unhandled rejection [1] ReferenceError: dashboard is not defined

shared.js 定义 dashboard:

var dashboard = { rows: [], }
// Other definitions...

define(["/app/custom-config.js", /* etc */]);

我想我有两个问题:

为了更完整的画面,main() 只需设置 dashboard 对象,然后对其调用 callbackFunction(dashboard)

您的问题可以简化为以下情况,您有两个 AMD 模块,一个泄漏到全局 space,第二个试图使用第一个泄漏的内容。喜欢下面两个模块。

src/a.js 需要泄漏的模块并取决于该模块泄漏的内容:

define(["./b"], function () {
    console.log("a loaded");
    callback();
});

src/b.js 泄漏到全局 space:

// This leaks `callback` into the global space.
var callback = function () { 
  console.log("callback called");
}
define(["./b"], function () {
    console.log("b loaded");
});

有了 RequireJS,上面的代码就可以工作了。哦,它设计得很糟糕因为b.js不应该泄漏到全局space,但它会起作用。您将在控制台上看到 callback called

使用 SystemJS,上面的代码将不起作用。为什么? RequireJS 通过向 header 添加一个 script 元素来加载模块,并让 script 执行模块的代码,因此 callback 最终确实在全局 space 中如果您使用指向脚本的 src 属性编写了自己的 script 元素,它也会采用同样的方式。 (你会得到一个 "Mismatched anonymous define" 错误,但这是一个单独的问题,不需要在这里耽搁我们。)SystemJS,默认情况下,使用 eval 而不是创建 script元素,这会改变代码的计算方式。 通常,这无关紧要,但有时确实如此。在手头的情况下,callback 不会在全局 space 中结束,模块 a 失败。

最终,您的 AMD 模块应该这样写,这样它们就不会使用全局 space 来相互传递信息。

但是,还有另一种解决方案可能对最终解决方案有用 stepping-stone。您可以使用 scriptLoad: true 告诉 SystemJS 使用 script 元素,就像 RequirejS 那样。 (有关详细信息和注意事项,请参阅 meta 上的文档。)这是执行此操作的配置:

System.config({
    baseURL: "src",
    meta: {
        "*": {
            scriptLoad: true, // This is what fixes the issue.
        }
    },
    packages: {
        // Yes, this empty package does something. It makes `.js` the
        // default extension for modules.
        "": {}
    },
});

// We have to put `define` in the global space to 
// so that our modules can find it.    
window.define = System.amdDefine;

如果我 运行 我在此处给出的示例代码没有 scriptLoad: true,则模块 a 无法调用回调。使用 scriptLoad: true,它可以调用回调,我进入控制台:

b loaded
a loaded
callback called