【问题标题】:requirejs() returns undefined when mixing node and amd modules混合 node 和 amd 模块时 requirejs() 返回 undefined
【发布时间】:2016-07-27 16:55:04
【问题描述】:

我正在尝试编写一些 JS 模块,它们应该可以在浏览器和 node.js 环境中使用。

为方便起见,我将这些模块编写为AMD modules,并使用requirejs in the Node.js environment 提供define() 函数以及加载这些模块的能力。

但是,我遇到了一些我不理解的行为。

我制作了一个 SSCCE 来说明问题:

├── bar.js
├── node_modules
│   └── foo
│       ├── foo.js
│       ├── index.js
│       ├── node_modules
│       │   └── requirejs
│       │       ├── bin
│       │       │   └── r.js
│       │       ├── package.json
│       │       ├── README.md
│       │       └── require.js
│       └── package.json
└── test.js

foo 是一个包含 AMD 模块 foo.js 的节点模块

node_modules/foo/foo.js

define([], function() {
    return function() {
        console.log("This is foo!");
    };
});

node_modules/foo/index.js

var requirejs = require('requirejs');

requirejs.config({
    baseUrl: __dirname,
    nodeRequire: require
});

module.exports = requirejs('foo');

bar.js 是另一个 AMD 模块:

define([], function() {
    return function() {
        console.log("This is bar!");
    };
});

test.js 是一个想要同时使用 foo 和 bar 的脚本:

var requirejs=require('requirejs');

requirejs.config(
    {
        baseUrl: __dirname, 
        nodeRequire: require
    }
);

var foo=require("foo");

foo();

var bar=requirejs("bar");

console.log("bar is:",bar);

如果我运行 test.js,我会得到:

This is foo!
bar is: undefined
/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:393
        throw err;
              ^
Error: Mismatched anonymous define() module: function () {
        return function() {
                console.log("This is bar!");
        };
}
http://requirejs.org/docs/errors.html#mismatch
    at makeError (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:418:17)
    at intakeDefines (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:1501:36)
    at null._onTimeout (/home/harmic/tmp/test_rjs/node_modules/foo/node_modules/requirejs/bin/r.js:1699:25)
    at Timer.listOnTimeout (timers.js:119:15)

这里有两件事对我来说没有意义。

  1. 在 test.js 中,对 requirejs("bar") 的调用返回 undef。事实上它看起来 模块的加载被延迟,好像有一些循环 依赖继续存在,因为只有在它返回之后 正在执行 bar 的模块定义。

  2. 为什么它认为这是一个匿名的define()?我的用例没有出现 以满足给定 URL 中的条件。

为了抑制第二个问题,我尝试在 bar.js 中命名定义,如下所示:

define('bar', [], function() {
...

这在异常消失的意义上有效,但requirejs("bar") 仍然 返回 undef。

该示例是我正在尝试做的简化版本 - 基本上我会 有许多模块,其中将包含一些常见的组件,可以 在浏览器和节点中使用,以及一些特定于节点的组件,它们只会 在节点中使用。模块之间会有依赖关系。

如果有更好的方法,那么我也愿意。

【问题讨论】:

  • requirejs("foo") 正在请求已加载到内存中的模块。试试 requirejs(["foo", "bar"], (foo, bar) => { foo() + bar() });
  • @CoreyAlix 根据the requirejs node docs 表示,在节点下,您可以使用requirejs("foo") 同步请求模块。这在包装 AMD 模块以在 Node 中使用时几乎是一个要求,因为 Node require() 是同步的。
  • bar.js 相对于您的其他文件位于何处?
  • @Louis 在项目根目录中,如第一张图所示。
  • 啊,这对我来说很尴尬。因为当我回答完你的问题时,我一开始就忘记了这一点。

标签: javascript node.js requirejs amd


【解决方案1】:

我已在本地重新创建了您在问题中显示的代码和层次结构,但我无法获得您报告的确切错误消息。我会说,看看您在问题中显示的内容,我不明白您的代码如何导致该错误消息。当我运行你的代码时,我得到的错误是:

This is foo!
/tmp/t1/node_modules/requirejs/bin/r.js:2604
                    throw err;
                    ^

Error: Tried loading "bar" at /tmp/t1/node_modules/foo/bar.js then tried node's require("bar") and it failed with error: Error: Cannot find module 'bar'
    at /tmp/t1/node_modules/requirejs/bin/r.js:2597:27

这正是我所期望的:在 node 中运行的 RequireJS 将尝试使用 Node 自己的require,如果它无法通过自己的机器找到模块。

现在,您遇到的问题不是在 Node 中运行 RequireJS 的问题,而是您如何使用 RequireJS 的问题。您可能会在浏览器中遇到完全相同的问题。问题是您运行requirejs.config 两次,而没有使用上下文,因此一个配置会覆盖另一个配置。 (RequireJS 能够合并配置,但您使用的配置会相互覆盖。)我可以通过更改 test.js 来运行代码,这样:

  1. RequireJS 的配置使用了context 值。

  2. 我保存requirejs.config的返回值并使用this来要求模块。

最终结果是:

var requirejs=require('requirejs');

var r = requirejs.config(
    {
        context: "me",
        baseUrl: __dirname,
        nodeRequire: require
    }
);

var foo=require("foo");

foo();

var bar= r("bar");

console.log("bar is:",bar);

理想情况下,index.js 中的代码也应该使用上下文。

话虽如此,多年来我已经编写了在 Node 和浏览器中作为 AMD 模块运行的代码。我很少需要在 Node.js 中使用 RequireJS 加载 AMD 模块。我想要这样做的一种罕见情况是,如果我正在测试模块如何通过module.config 获取其配置。我从来没有发现需要使用amdefine。当我想在 Node 中加载 AMD 模块时,我使用的是 amd-loader(又名 node-amd-loader)。它只是挂钩到 Node 的模块加载机制,使其能够加载 AMD 模块。我猜 amd-loader 的缺点是想要使用你的代码的项目必须依赖安装像 amd-loader 这样的加载器。

【讨论】:

    【解决方案2】:

    最后我没有得到满意的答案。

    在 node.js 环境中使用这些模块时,我通过使用 amdefine 解决了这个问题,而不是尝试使用 requirejs。

    这种方法的主要缺点是您必须在所有 AMD 模块的前面添加一些样板,以便它们在需要时加载 amdefine,但除此之外,amdefine 至少适用于我的用例。

    我还找到了UMD 项目,它提供了一些其他选择。

    【讨论】:

      猜你喜欢
      • 2012-05-28
      • 1970-01-01
      • 2017-04-24
      • 2021-11-05
      • 2019-05-12
      • 2017-02-08
      • 2013-07-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多