当混合node和amd模块时,requirejs()返回undefined
requirejs() returns undefined when mixing node and amd modules
我正在尝试编写一些JS模块,这些模块应该可以在浏览器和node.JS环境中使用。
为了方便起见,我将这些模块编写为AMD模块,并在Node.js环境中使用requirejs来提供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)
有两件事对我来说没有意义。
在test.js中,对
requirejs("bar")
的调用返回undef。事实上,它看起来模块的加载被推迟,就好像有一些循环依赖性仍在继续,因为只有在它返回后正在执行bar的模块定义。为什么它认为这是一个匿名的
define()
?我的用例没有出现以满足给定URL中的标准。
为了解决第二个问题,我尝试在bar.js中命名define,如下所示:
define('bar', [], function() {
...
这在某种意义上是有效的,即异常已经消失,但requirejs("bar")
仍然存在返回undef。
这个例子是我尝试做的事情的简化版本——基本上我会具有多个模块,这些模块将包含一些可以在浏览器和节点中使用,以及一些仅会在节点中使用。模块之间将存在依赖关系。
如果有更好的方法可以做到这一点,那么我也持开放态度。
我已经在本地重新创建了您在问题中显示的代码和层次结构,但我无法获得您报告的确切错误消息。我想说,看看你在问题中显示的内容,我不明白你的代码是如何导致错误消息的。当我运行你的代码时,我得到的错误是:
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无法通过自己的机器找到模块,那么运行在node中的RequireJS将尝试使用node自己的require
。
现在,您遇到的问题不是在Node中运行RequireJS的问题,而是如何使用RequireJS的一个问题。你可能会在浏览器中遇到完全相同的问题。问题是,您在不使用上下文的情况下运行了两次requirejs.config
,因此一个配置会覆盖另一个配置。(RequireJS可以合并配置,但您使用的配置会相互覆盖。)我可以通过更改test.js
来运行代码,以便:
RequireJS的配置使用
context
值。我保存
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中加载带有RequireJS的AMD模块。我想这样做的一个罕见情况是,如果我正在测试模块如何通过module.config
进行配置。我从未发现有必要使用amdefine。当我想在Node中加载AMD模块时,我使用的是AMD加载器(又名Node AMD加载器)。它只是挂在Node的模块加载机器上,使其能够加载AMD模块。我想amd-loader的缺点是,想要使用你的代码的项目必须依赖于安装像amd-loader一样的加载程序。
最后我没有得到任何令人满意的答案。
我在node.js环境中使用这些模块时使用了amdefine,而不是尝试使用requirejs。
这种方法的主要缺点是,您必须在所有AMD模块的前面添加一些样板,以便在需要时加载amdefine,但除此之外,amdefine至少适用于我的用例。
我还发现了UMD项目,它提供了一些其他的替代方案。
- 节点导出返回一个空对象
- ES6构造函数返回基类的实例
- 监视函数从服务返回不起作用,但作用域函数起作用
- 控制台返回var不是't定义,但它是
- 从函数返回角度承诺
- Javascript返回值只在循环中返回一次
- RequireJS向模块传递配置总是返回undefined
- 当混合node和amd模块时,requirejs()返回undefined
- 为什么在使用requirejs定义我的模块时需要返回
- 返回 XMLHttpRequest 的 RequireJS + NodeJS 无法加载“http”,没有“Access-
- requireJS包含返回另一个类似模块中的对象的模块
- 为什么在使用返回的RequireJS函数中声明的Click绑定时未定义
- Angular+Requirejs-如何返回多个模块
- RequireJS module.config()总是返回undefined
- RequireJS定义了返回错误模块依赖的回调
- ReactJS和RequireJS ->如何使用从一个模块返回的多个类
- jquery.active总是返回0 (jquery和requireJS)
- requirejs返回一个带有attach和notNeeded方法的模块
- RequireJS模块从API服务器接收JSON,返回undefined
- require如何在requireJS中使用动态名称时返回相同的文件