将"Vanilla"Javascript库加载到Node.js中

Chr*_* W. 106 javascript commonjs node.js

有一些第三方Javascript库具有我想在Node.js服务器中使用的一些功能.(具体来说,我想使用我发现的QuadTree javascript库.)但这些库只是简单的.js文件而不是"Node.js库".

因此,这些库不遵循exports.var_nameNode.js对其模块所期望的语法.据我了解,这意味着当你这样做module = require('module_name');或者module = require('./path/to/file.js');你最终会得到一个没有公共可访问功能的模块等.

我的问题是"我如何将任意javascript文件加载到Node.js中,以便我可以利用它的功能,而不必重写它,以便它可以做到exports?"

我对Node.js很新,所以如果我对它的工作原理有一些明显的漏洞,请告诉我.


编辑:研究更多东西,我现在看到Node.js使用的模块加载模式实际上是最近开发的加载Javascript库的标准的一部分,称为CommonJS.它在Node.js模块文档页面上说明了这一点,但直到现在我才错过了.

可能最终我的问题的答案是"等到你的图书馆的作者开始写一个CommonJS界面或者做你自己该死的自己."

Chr*_* W. 79

以下是我认为这种情况的"最正确"答案.

假设您有一个名为的脚本文件quadtree.js.

您应该构建node_module具有此类目录结构的自定义...

./node_modules/quadtree/quadtree-lib/
./node_modules/quadtree/quadtree-lib/quadtree.js
./node_modules/quadtree/quadtree-lib/README
./node_modules/quadtree/quadtree-lib/some-other-crap.js
./node_modules/quadtree/index.js
Run Code Online (Sandbox Code Playgroud)

./node_modules/quadtree/quadtree-lib/目录中的所有内容都是第三方库中的文件.

然后你的./node_modules/quadtree/index.js文件将从文件系统加载该库,并正确地导出东西.

var fs = require('fs');

// Read and eval library
filedata = fs.readFileSync('./node_modules/quadtree/quadtree-lib/quadtree.js','utf8');
eval(filedata);

/* The quadtree.js file defines a class 'QuadTree' which is all we want to export */

exports.QuadTree = QuadTree
Run Code Online (Sandbox Code Playgroud)

现在您可以quadtree像任何其他节点模块一样使用您的模块......

var qt = require('quadtree');
qt.QuadTree();
Run Code Online (Sandbox Code Playgroud)

我喜欢这种方法,因为不需要更改第三方库的任何源代码 - 所以它更容易维护.升级所需要做的就是查看源代码并确保仍在导出正确的对象.

  • 如果您完全遵循这一点,请记住,使用NPM意外删除node_modules文件夹非常容易,特别是如果您不将其检入SCM.绝对考虑将您的QuadTree库放在一个单独的存储库中,然后`npm将它链接到您的应用程序中.然后它被处理就好像它是一个本机Node.js包. (8认同)
  • 刚刚找到你的答案(制作一个多人游戏并需要在服务器和客户端中包含JigLibJS,我们的物理引擎)你为我节省了大量的时间和麻烦.谢谢! (3认同)

Dav*_*ver 73

有一个比使用更好的方法eval:vm模块.

例如,这是我的execfile模块,它path在任一context或全局上下文中评估脚本:

var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
  context = context || {};
  var data = fs.readFileSync(path);
  vm.runInNewContext(data, context, path);
  return context;
}
Run Code Online (Sandbox Code Playgroud)

它可以像这样使用:

> var execfile = require("execfile");
> // `someGlobal` will be a global variable while the script runs
> var context = execfile("example.js", { someGlobal: 42 });
> // And `getSomeGlobal` defined in the script is available on `context`:
> context.getSomeGlobal()
42
> context.someGlobal = 16
> context.getSomeGlobal()
16
Run Code Online (Sandbox Code Playgroud)

其中example.js包括:

function getSomeGlobal() {
    return someGlobal;
}
Run Code Online (Sandbox Code Playgroud)

这种方法的最大优点是你可以完全控制执行脚本中的全局变量:你可以传入自定义全局变量(via context),并且将添加脚本创建的所有全局变量context.调试也更容易,因为将使用正确的文件名报告语法错误等.

  • 有关此方法优于eval的原因的说明,请参阅我的更新. (2认同)

Chr*_*iss 30

最简单的方法是:eval(require('fs').readFileSync('./path/to/file.js', 'utf8')); 这非常适合在交互式shell中进行测试.


Mar*_*ijn 5

AFAIK,确实是必须加载模块的.但是,exports您可以将所有导出的函数添加到对象上this(而不是将其作为全局对象).

因此,如果您想保持其他库兼容,您可以这样做:

this.quadTree = function () {
  // the function's code
};
Run Code Online (Sandbox Code Playgroud)

或者,当外部库已经有自己的命名空间时,例如jQuery(不是你可以在服务器端环境中使用):

this.jQuery = jQuery;
Run Code Online (Sandbox Code Playgroud)

在非Node环境中,this将解析为全局对象,从而使其成为全局变量......它已经存在.所以它不应该破坏任何东西.

编辑:James Herdman 为初学者提供了关于node.js 的精彩文章,其中也提到了这一点.