在node.js中加载和执行外部js文件并可以访问局部变量?


130

include('./path/to/file')在node.js中执行简单类型的命令是否容易/可行?

我要做的就是访问局部变量并运行脚本。人们通常如何组织比简单的hello世界更大的node.js项目?(功能齐全的动态网站)

例如,我想拥有类似的目录:

/models

/views

...等等


也可以包含来自外部URL(而不是本地文件)的脚本。看到这里:pastebin.com/WkvHjGsG
Anderson Green

仅当您downloadedModules在与脚本相同的目录中创建一个文件夹时,以上脚本才能正常工作。
Anderson Green

Answers:


134

只是做一个 require('./yourfile.js');

将您希望外部访问的所有变量声明为全局变量。所以代替

var a = "hello" 这将是

GLOBAL.a="hello" 要不就

a = "hello"

这显然是不好的。您不想污染全局范围。相反,建议方法是针对export您的函数/变量。

如果您想要MVC模式,请查看Geddy。


3
作为附带说明..我喜欢快递。如果您对MVC不那么特别,那么您也应该检查一下。
Shripad Krishna 2010年

42
当您说“这显然不好”时,“这个”指的是什么?
安德森·格林

1
@AndersonGreen-他的意思是将变量放入全局范围。
蒂姆(Tim)

77
@AndersonGreen:请告诉我,这是关于范围界定的一个非常聪明的笑话;-)
Dusty J

6
require如果您未在路径中添加类似以下内容的前缀,这将有助于我了解npm模块中的外观./
Dylan Valade 2015年

93

您需要了解CommonJS,这是定义模块的一种模式。您不应该滥用GLOBAL范围,这总是一件坏事,而可以使用'exports'令牌,如下所示:

// circle.js

var PI = 3.14; // PI will not be accessible from outside this module

exports.area = function (r) {
  return PI * r * r;
};

exports.circumference = function (r) {
  return 2 * PI * r;
};

以及将使用我们的模块的客户端代码:

// client.js

var circle = require('./circle');
console.log( 'The area of a circle of radius 4 is '
           + circle.area(4));

此代码是从node.js文档API中提取的:

http://nodejs.org/docs/v0.3.2/api/modules.html

另外,如果您想使用Rails或Sinatra之类的东西,我建议您使用Express(我无法发布该URL,这对Stack Overflow很可惜!)


64

如果您正在为Node编写代码,那么使用Ivan所述的Node模块无疑是正确的选择。

但是,如果您需要加载已经编写的并且不知道节点的JavaScript,那么使用该vm模块是可行的(并且绝对更可取eval)。

例如,这是我的execfile模块,该模块pathcontext或全局上下文中评估脚本:

var vm = require("vm");
var fs = require("fs");
module.exports = function(path, context) {
  var data = fs.readFileSync(path);
  vm.runInNewContext(data, context, path);
}

另请注意:加载了的模块require(…)无权访问全局上下文。


1
感谢您的提示。真正的用例是当您需要加载临时模块时。就像注册模式一样,您将有1000个模块在中央服务中进行注册。扫描模块并逐个加载模块,而不是在服务中执行1000条require语句,这是一种更干净,更好的设计……
Assaf Moldavsky

Node支持动态需求,因此在动态加载支持Node的模块时没有理由使用此模式。实际上,在此使用它会非常有害,因为它会绕过Node的require.cache,因此单个文件可能会多次加载。
David Wolever '16

好的,要解决我提出的情况,即您有1000个模块要在每个模块中注册到注册服务,那么如何使用建议的内容而不在注册表服务中有1000个req​​uire语句?
阿萨夫·摩尔达夫斯基

1
只是require像正常:function loadService(name) { return require('./services/' + name); }然后列出但是服务是有道理的应用。
David Wolever '18

是的,但这意味着您必须了解注册表服务中的所有1000个模块。这比拥有1000条require语句更好。整个想法是,注册表服务并不了解所有模块,实际上它确实在乎它们。模块将临时性注册到注册服务。那有意义吗?
阿萨夫·摩尔达夫斯基

7

如果您打算加载外部javascript文件的函数或对象,请使用以下代码在此上下文上加载–请注意runInThisContext方法:

var vm = require("vm");
var fs = require("fs");

var data = fs.readFileSync('./externalfile.js');
const script = new vm.Script(data);
script.runInThisContext();

// here you can use externalfile's functions or objects as if they were instantiated here. They have been added to this context. 

2
经过大量搜索和摸索,这项技术对我有用。我的文件供浏览器直接使用并声明一个变量,例如:const aVar = {something:'a'}
lucsan

3

扩展@Shripad@Ivan的答案,我建议您使用Node.js的标准module.export功能。

在常量文件(例如 constants.js)中,您可以这样编写常量:

const CONST1 = 1;
module.exports.CONST1 = CONST1;

const CONST2 = 2;
module.exports.CONST2 = CONST2;

然后在要使用这些常量的文件中,编写以下代码:

const {CONST1 , CONST2} = require('./constants.js');

如果您以前从未看过const { ... }语法:那是在破坏分配


0

抱歉复活。您可以使用child_process模块​​在node.js中执行外部js文件

var child_process = require('child_process');

//EXECUTE yourExternalJsFile.js
child_process.exec('node yourExternalJsFile.js', (error, stdout, stderr) => {
    console.log(`${stdout}`);
    console.log(`${stderr}`);
    if (error !== null) {
        console.log(`exec error: ${error}`);
    }
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.