Javascript 如何检查脚本是否在 Node.js 下运行?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4224606/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to check whether a script is running under Node.js?
提问by theosp
I have a script I am requiring from a Node.js script, which I want to keep JavaScript engine independent.
我有一个需要来自 Node.js 脚本的脚本,我希望它保持 JavaScript 引擎独立。
For example, I want to do exports.x = y;
only if it's running under Node.js. How can I perform this test?
例如,我只想exports.x = y;
在它在 Node.js 下运行时才这样做。我该如何执行此测试?
When posting this question, I didn't know the Node.js modules feature is based on CommonJS.
在发布这个问题时,我不知道 Node.js 模块功能是基于CommonJS 的。
For the specific example I gave, a more accurate question would've been:
对于我给出的具体示例,更准确的问题是:
How can a script tell whether it has been required as a CommonJS module?
脚本如何判断它是否需要作为 CommonJS 模块?
采纳答案by Ross
By looking for CommonJS support, this is how the Underscore.jslibrary does it:
通过寻找 CommonJS 支持,Underscore.js库是这样做的:
Edit: to your updated question:
编辑:对您更新的问题:
(function () {
// Establish the root object, `window` in the browser, or `global` on the server.
var root = this;
// Create a reference to this
var _ = new Object();
var isNode = false;
// Export the Underscore object for **CommonJS**, with backwards-compatibility
// for the old `require()` API. If we're not in CommonJS, add `_` to the
// global object.
if (typeof module !== 'undefined' && module.exports) {
module.exports = _;
root._ = _;
isNode = true;
} else {
root._ = _;
}
})();
Example here retains the Module pattern.
这里的示例保留了模块模式。
回答by Ivo Wetzel
Well there's no reliable way to detect running in Node.js since every website could easily declare the same variables, yet, since there's no window
object in Node.js by default you can go the other way around and check whether you're running inside a Browser.
好吧,没有可靠的方法来检测 Node.js 中的运行情况,因为每个网站都可以轻松声明相同的变量,但是,由于window
默认情况下 Node.js 中没有对象,您可以反过来检查您是否在内部运行浏览器。
This is what I use for libs that should work both in a Browser and under Node.js:
这是我用于应该在浏览器和 Node.js 下都可以工作的库的内容:
if (typeof window === 'undefined') {
exports.foo = {};
} else {
window.foo = {};
}
It might still explode in case that window
is defined in Node.js but there's no goodreason for someone do this, since you would explicitly need to leave out var
or set the property on the global
object.
如果它window
在 Node.js 中定义,它可能仍然会爆炸,但没有充分的理由让某人这样做,因为您需要明确地省略var
或设置global
对象的属性。
EDIT
编辑
For detecting whether your script has been required as a CommonJS module, that's again not easy. Only thing commonJS specifies is that A: The modules will be included via a call to the function require
and B: The modules exports things via properties on the exports
object. Now how that is implement is left to the underlying system. Node.js wraps the module's content in an anonymous function:
要检测您的脚本是否需要作为 CommonJS 模块,这又不是一件容易的事。commonJS 唯一指定的是 A:模块将通过对函数的调用包含在内,require
而 B:模块通过exports
对象上的属性导出事物。现在如何实现留给底层系统。Node.js 将模块的内容包装在一个匿名函数中:
function (exports, require, module, __filename, __dirname) {
See: https://github.com/ry/node/blob/master/src/node.js#L325
参见:https: //github.com/ry/node/blob/master/src/node.js#L325
But don'ttry to detect that via some crazy arguments.callee.toString()
stuff, instead just use my example code above which checks for the Browser. Node.js is a way cleaner environment so it's unlikely that window
will be declared there.
但是不要试图通过一些疯狂的arguments.callee.toString()
东西来检测它,而只是使用我上面检查浏览器的示例代码。Node.js 是一种更清洁的环境,因此不太可能window
在那里声明。
回答by Florian Breisch
I currently stumbled over a wrong detection of Node which is notaware of the Node-environment in Electrondue to a misleading feature-detection. The following solutions identify the process-environment explicitly.
我目前偶然发现了错误的 Node 检测,由于误导性的特征检测,它不知道Electron中的 Node 环境。以下解决方案明确标识流程环境。
Identify Node.js only
仅识别 Node.js
(typeof process !== 'undefined') && (process.release.name === 'node')
This will discover if you're running in a Node-process, since process.release
contains the "metadata related to the current [Node-]release".
这将发现您是否在 Node 进程中运行,因为process.release
包含“与当前 [Node-] 版本相关的元数据”。
After the spawn of io.jsthe value of process.release.name
may also become io.js
(see the process-doc). To proper detect a Node-ready environment i guess you should check as follows:
在io.js产生之后,的值process.release.name
也可能变成io.js
(参见process-doc)。为了正确检测 Node-ready 环境,我想你应该检查如下:
Identify Node (>= 3.0.0) or io.js
识别节点 (>= 3.0.0) 或 io.js
(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)
This statement was tested with Node 5.5.0, Electron 0.36.9 (with Node 5.1.1) and Chrome 48.0.2564.116.
此语句已使用 Node 5.5.0、Electron 0.36.9(使用 Node 5.1.1)和 Chrome 48.0.2564.116 进行测试。
Identify Node (>= 0.10.0) or io.js
识别节点 (>= 0.10.0) 或 io.js
(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')
@daluege's comment inspired me to think about a more general proof. This should working from Node.js >= 0.10. I didn't find a unique identifier for prior versions.
@daluege 的评论启发我去思考一个更一般的证明。这应该适用于 Node.js >= 0.10。我没有找到以前版本的唯一标识符。
P.s.: I am posting that answer here since the question lead me here, although the OP was searching for an answer to a different question.
Ps:我在这里发布了这个答案,因为这个问题把我带到了这里,尽管 OP 正在寻找另一个问题的答案。
回答by TimE
The problem with trying to figure out what environment your code is running in is that any object can be modified and declared making it close to impossible to figure out which objects are native to the environment, and which have been modified by the program.
试图弄清楚你的代码在什么环境中运行的问题在于,任何对象都可以被修改和声明,这使得几乎不可能确定哪些对象是环境本机的,哪些已经被程序修改了。
However, there are a few tricks we can use to figure out for sure what environment you are in.
但是,我们可以使用一些技巧来确定您所处的环境。
Lets start out with the generally accepted solution that's used in the underscore library:
让我们从下划线库中使用的普遍接受的解决方案开始:
typeof module !== 'undefined' && module.exports
typeof module !== 'undefined' && module.exports
This technique is actually perfectly fine for the server side, as when the require
function is called, it resets the this
object to an empty object, and redefines module
for you again, meaning you don't have to worry about any outside tampering. As long as your code is loaded in with require
, you are safe.
这种技术对于服务器端实际上非常好,因为当require
调用该函数时,它会将this
对象重置为空对象,然后module
再次为您重新定义,这意味着您不必担心任何外部篡改。只要您的代码加载了require
,您就是安全的。
However, this falls apart on the browser, as anyone can easily define module
to make it seem like it's the object you are looking for. On one hand this might be the behavior you want, but it also dictates what variables the library user can use in the global scope. Maybe someone wants to use a variable with the name module
that has exports
inside of it for another use. It's unlikely, but who are we to judge what variables someone else can use, just because another environment uses that variable name?
但是,这在浏览器上会失效,因为任何人都可以轻松定义module
以使其看起来像是您正在寻找的对象。一方面,这可能是您想要的行为,但它也决定了库用户可以在全局范围内使用哪些变量。也许有人想将一个名称module
包含exports
在其中的变量用于其他用途。这不太可能,但是我们凭什么来判断其他人可以使用哪些变量,仅仅因为另一个环境使用该变量名称?
The trick however, is that if we are assuming that your script is being loaded in the global scope (which it will be if it's loaded via a script tag) a variable cannot be reserved in an outer closure, because the browser does not allow that. Now remember in node, the this
object is an empty object, yet, the module
variable is still available. That is because it's declared in an outer closure. So we can then fix underscore's check by adding an extra check:
然而,诀窍是,如果我们假设您的脚本是在全局范围内加载的(如果它是通过脚本标签加载的),则不能在外部闭包中保留变量,因为浏览器不允许这样做. 现在记住在节点中,this
对象是一个空对象,但module
变量仍然可用。那是因为它是在外部闭包中声明的。所以我们可以通过添加一个额外的检查来修复下划线的检查:
this.module !== module
this.module !== module
With this, if someone declares module
in the global scope in the browser, it will be placed in the this
object, which will cause the test to fail, because this.module
, will be the same object as module. On node, this.module
does not exist, and module
exists within an outer closure, so the test will succeed, as they are not equivalent.
有了这个,如果有人module
在浏览器中的全局范围内声明,它就会被放置在this
对象中,这将导致测试失败,因为this.module
, 将是与模块相同的对象。在节点上,this.module
不存在,并且module
存在于外部闭包中,因此测试将成功,因为它们不等价。
Thus, the final test is:
因此,最终的测试是:
typeof module !== 'undefined' && this.module !== module
typeof module !== 'undefined' && this.module !== module
Note: While this now allows the module
variable to be used freely in the global scope, it is still possible to bypass this on the browser by creating a new closure and declaring module
within that, then loading the script within that closure. At that point the user is fully replicating the node environment and hopefully knows what they are doing and is trying to do a node style require. If the code is called in a script tag, it will still be safe from any new outer closures.
注意:虽然这现在允许module
在全局范围内自由使用变量,但仍然可以通过创建一个新的闭包并module
在其中声明,然后在该闭包中加载脚本来绕过浏览器上的这一点。此时,用户正在完全复制节点环境,并希望知道他们在做什么,并正在尝试执行节点样式要求。如果代码在脚本标签中被调用,它对于任何新的外部闭包仍然是安全的。
回答by user3751385
The following works in the browser unless intentionally,explicitly sabotaged:
除非故意,明确破坏,否则以下内容在浏览器中有效:
if(typeof process === 'object' && process + '' === '[object process]'){
// is node
}
else{
// not node
}
Bam.
砰。
回答by Patrick
Here's a pretty cool way to do it as well:
这也是一个非常酷的方法:
const isBrowser = this.window === this;
This works because in browsers the global 'this' variable has a self reference called 'window'. This self reference is not existent in Node.
这是有效的,因为在浏览器中,全局“this”变量有一个名为“window”的自引用。这个自引用在 Node.js 中不存在。
- In the browser 'this' is a reference to the global object, called 'window'.
- In Node 'this' is a reference to the module.exports
object.
- 'this' is nota reference to the Node global object, called 'global'.
- 'this' is nota reference to the the module variable declaration space.
- 在浏览器中,“this”是对全局对象的引用,称为“window”。
- 在 Node 中,'this' 是对 module.exports 对象的引用。
- “this”不是对称为“global”的 Node 全局对象的引用。
- 'this'不是对模块变量声明空间的引用。
To break the above suggested browser check you would have to do something like the following
要打破上述建议的浏览器检查,您必须执行以下操作
this.window = this;
before executing the check.
在执行检查之前。
回答by Onur Y?ld?r?m
Yet another environment detection:
另一个环境检测:
(Meaning: most of the answers here are alright.)
(意思是:这里的大多数答案都很好。)
function isNode() {
return typeof global === 'object'
&& String(global) === '[object global]'
&& typeof process === 'object'
&& String(process) === '[object process]'
&& global === global.GLOBAL // circular ref
// process.release.name cannot be altered, unlike process.title
&& /node|io\.js/.test(process.release.name)
&& typeof setImmediate === 'function'
&& setImmediate.length === 4
&& typeof __dirname === 'string'
&& Should I go on ?..
}
A bit paranoid right? You can make this more verbose by checking for more globals.
有点偏执吧?您可以通过检查 more globals来使这更详细。
But DON'T!.
但不要!
All these above can be faked/simulated anyway.
无论如何,以上所有这些都可以伪造/模拟。
For example to fake the global
object:
例如伪造global
对象:
global = {
toString: function () {
return '[object global]';
},
GLOBAL: global,
setImmediate: function (a, b, c, d) {}
};
setImmediate = function (a, b, c, d) {};
...
This won't get attached to the Node's original global object but it will get attached to the window
object in a browser. So it'll imply that you're in Node env inside a browser.
这不会附加到节点的原始全局对象,但会附加到window
浏览器中的对象。所以这意味着你在浏览器中的 Node 环境中。
Life is short!
生命短暂!
Do we care if our environment is faked? It'd happen when some stupid developer declare a global variable called global
in the global scope. Or some evil dev injects code in our env somehow.
我们是否关心我们的环境是否是伪造的?当一些愚蠢的开发人员声明一个global
在全局范围内调用的全局变量时,就会发生这种情况。或者一些邪恶的开发人员以某种方式在我们的环境中注入了代码。
We may prevent our code from executing when we catch this but lots of other dependencies of our app might get caught into this. So eventually the code will break. If your code is good enough, you should not care for each and every silly mistake that could have been done by others.
当我们捕捉到这个时,我们可能会阻止我们的代码执行,但是我们的应用程序的许多其他依赖项可能会被捕捉到。所以最终代码会崩溃。如果你的代码足够好,你就不应该关心其他人可能犯的每一个愚蠢的错误。
So what?
所以呢?
If targeting 2 environments: Browser and Node;"use strict"
; and either simply check for window
or global
; and clearly indicate that in the docs that your code supports only these environments. That's it!
如果针对 2 个环境:浏览器和节点;"use strict"
; 或者简单地检查window
或global
;并在文档中明确指出您的代码仅支持这些环境。就是这样!
var isBrowser = typeof window !== 'undefined'
&& ({}).toString.call(window) === '[object Window]';
var isNode = typeof global !== "undefined"
&& ({}).toString.call(global) === '[object global]';
If possible for your use case; instead of environment detection; do synchronous feature detection within a try/catch block. (these will take a few milliseconds to execute).
如果可能适用于您的用例;代替环境检测;在 try/catch 块内进行同步特征检测。(这些将需要几毫秒来执行)。
e.g.
例如
function isPromiseSupported() {
var supported = false;
try {
var p = new Promise(function (res, rej) {});
supported = true;
} catch (e) {}
return supported;
}
回答by Fabian Jakobs
Most of the proposed solutions can actually be faked. A robust way is to check the internal Class
property of the global object using the Object.prototype.toString
. The internal class can't be faked in JavaScript:
大多数提议的解决方案实际上可以伪造。一种可靠的方法是Class
使用Object.prototype.toString
. 内部类不能在 JavaScript 中伪造:
var isNode =
typeof global !== "undefined" &&
{}.toString.call(global) == '[object global]';
回答by Kevin Hakanson
回答by Chris
I'm using process
to check for node.js like so
我正在process
像这样检查 node.js
if (typeof(process) !== 'undefined' && process.version === 'v0.9.9') {
console.log('You are running Node.js');
} else {
// check for browser
}
or
或者
if (typeof(process) !== 'undefined' && process.title === 'node') {
console.log('You are running Node.js');
} else {
// check for browser
}
Documented here
记录在这里