我正在尝试编写一些应该可以在浏览器和node.js环境中使用的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.js
define([], function() {
return function() {
console.log("This is foo!");
};
});
node_modules /富/ 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()
?我的用例没有出现
满足给定网址中的条件。
为了抑制第二个问题,我尝试在bar.js中命名define,如下所示:
define('bar', [], function() {
...
在异常消失的意义上有效,但requirejs("bar")
仍然存在
返回undef。
这个例子是我想要做的简化版本 - 基本上我会 有许多模块,其中包含一些可以使用的常见组件 用于浏览器和节点,以及一些特定于节点的组件 在节点中使用。模块之间将存在依赖关系。
如果有更好的方法可以做到这一点,那么我也可以这样做。
答案 0 :(得分: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
这正是我所期望的:如果在节点中运行的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-loader(又名node-amd-loader)。它只是挂钩Node的模块加载机器,使其能够加载AMD模块。我想amd-loader的缺点是那些想要使用你的代码的项目必须依赖于像amd-loader那样安装一个加载器。
答案 1 :(得分:0)