如何检查一个脚本是否在node.js下运行?

时间:2021-06-02 16:24:40

I have a script I am requiring from a node.js script, which I want to keep javascript engine independent.

我有一个从节点中需要的脚本。js脚本,我想保持javascript引擎的独立性。

So, for example, I want to do:

举个例子,我想说

exports.x = y;

only if it's running under node.js. how can I perform this test?

只有在node.js下运行时。我如何执行这个测试?

Edit: When posting this question, I didn't know the node.js modules feature is based on commonjs.

编辑:当我发布这个问题时,我不知道这个节点。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模块被要求?

17 个解决方案

#1


71  

This is how the Underscore.js library does it (by looking for CommonJS support):

这就是下划线。js库(通过查找CommonJS支持):

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.

这里的示例保留了模块模式。

#2


68  

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.

没有可靠的方法来检测在节点中运行的情况。因为每个网站都可以很容易地声明相同的变量,但是,因为节点中没有窗口对象。默认情况下,你可以反过来检查你是否在浏览器中运行。

This is what I use for libs that should work both in a Browser and under Node.js:

这就是我对libs的使用,它应该在浏览器和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 good reason for someone do this, since you would explicitly need to leave out var or set the property on the global object.

如果在Node中定义了窗口,它可能仍然会爆炸。但是没有理由有人这样做,因为您需要显式地删除var或设置全局对象上的属性。

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 modules content in an anonymous funciton.

要检测您的脚本作为CommonJS模块是否必需,这同样不容易。commonJS只指定A:模块将通过调用函数require来包含,B:模块通过export对象上的属性导出。现在实现的方式留给底层系统。节点。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't go there by trying 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.

但是,不要通过一些疯狂的参数来检测它,而是使用上面的示例代码检查浏览器Node。js是一种更干净的环境,所以不太可能在那里声明窗口。

#3


25  

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

模块类型!== '未定义' && module。导出。

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函数时,它会将这个对象重置为一个空对象,并为您重新定义模块,这意味着您不必担心任何外部干扰。只要您的代码装载了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?

但是,这在浏览器上是行不通的,因为任何人都可以很容易地定义模块,使它看起来像是您正在寻找的对象。一方面,这可能是您想要的行为,但它也规定了库用户可以在全局范围中使用哪些变量。可能有人想要使用一个带有name模块的变量,该模块内部有导出供其他使用。这是不可能的,但是我们谁来判断其他人可以使用什么变量,仅仅因为另一个环境使用了那个变量名?

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:

但是,关键在于,如果我们假设您的脚本正在全局范围内加载(如果它是通过脚本标签加载的),那么不能在外部闭包中保留变量,因为浏览器不允许这样做。记住,在node中,这个对象是一个空对象,但是,模块变量仍然可用。这是因为它是在外部闭包中声明的。因此我们可以通过增加一个额外的检查来修复下划线的检查:

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.

有了这个,如果有人在浏览器的全局范围中声明模块,它将被放置在这个对象中,这会导致测试失败,因为这一点。模块,将与模块相同的对象。在节点,这个。模块不存在,模块存在于外部闭包中,因此测试将会成功,因为它们并不相等。

Thus, the final test is:

因此,最后的测试是:

typeof module !== 'undefined' && this.module !== module

= 'undefined' & this。模块! = =模块

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.

注意:虽然现在允许在全局范围内*使用模块变量,但仍有可能在浏览器中创建一个新的闭包和声明模块,然后在该闭包中加载脚本。此时,用户正在完全复制节点环境,并希望知道他们正在做什么,并尝试执行节点样式所需的操作。如果在脚本标记中调用代码,它仍然不会受到任何新的外部闭包的影响。

#4


21  

The following works in the browser unless intentionally,explicitly sabotaged:

以下在浏览器中工作,除非故意、明确地破坏:

if(typeof process === 'object' && process + '' === '[object process]'){
    // is node
}
else{
    // not node
}

Bam.

Bam。

#5


20  

I currently stumbled over a wrong detection of Node which is not aware of the Node-environment in Electron due to a misleading feature-detection. The following solutions identify the process-environment explicitly.

我最近偶然发现了一个错误的节点检测,由于一个错误的特性检测,它不知道电子中的节点环境。下面的解决方案明确地标识了流程环境。


Identify Node.js only

(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".

如果您正在一个节点进程中运行,这将会发现,因为进程。release包含“与当前[Node-]release相关的元数据”。

After the spawn of io.js the 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的衍生之后。进程.release.name的值也可能变成io。js(参见process-doc)。为了正确检测节点就绪的环境,我想你应该检查以下内容:

Identify Node (>= 3.0.0) or 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.

该语句使用节点5.5.0、电子0.36.9(节点5.1.1)和Chrome 48.0.2564.116进行测试。

Identify Node (>= 0.10.0) or 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.

注。我在这里张贴这个答案,因为这个问题把我带到了这里,尽管OP正在寻找另一个问题的答案。

#6


9  

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:

大多数提出的解决方案实际上都是可以伪造的。一种健壮的方法是使用object .prototype. tostring检查全局对象的内部类属性。内部类不能用JavaScript伪造:

var isNode = 
    typeof global !== "undefined" && 
    {}.toString.call(global) == '[object global]';

#7


9  

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.

有点偏执的对吧?通过检查更多的全局变量,您可以使它更加详细。

But DON'T!.

All these above can be faked/simulated anyway.

以上这些都可以伪造/模拟。

For example to fake the global object:

例如伪造全局对象:

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.

它不会连接到节点的原始全局对象,但会连接到浏览器中的窗口对象。它会暗示你在浏览器内的节点env。

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的全局变量时,就会发生这种情况。或者一些邪恶的开发人员以某种方式向我们的env注入代码。

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!

如果针对两个环境:浏览器和节点;“使用严格的”;或者简单地检查窗口或全局;并且在文档中清楚地表明您的代码只支持这些环境。就是这样!

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;
}

#8


8  

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”的自引用。这个自引用在节点中不存在。

  • In the browser 'this' is a reference to the global object, called 'window'.
  • 在浏览器中,“this”是对全局对象的引用,称为“窗口”。
  • In Node 'this' is a reference to the module.exports object.
    • 'this' is not a reference to the Node global object, called 'global'.
    • 'this'不是对节点全局对象的引用,称为'global'。
    • 'this' is not a reference to the the module variable declaration space.
    • 'this'不是对模块变量声明空间的引用。
  • 在Node 'this'是对模块的引用。出口对象。'this'不是对节点全局对象的引用,称为'global'。'this'不是对模块变量声明空间的引用。

To break the above suggested browser check you would have to do something like the following

要打破上面建议的浏览器检查,您需要做如下操作

this.window = this;

before executing the check.

在执行之前检查。

#9


4  

What about using the process object and checking execPath for node?

如何使用流程对象并检查节点的execPath ?

process.execPath

process.execPath

This is the absolute pathname of the executable that started the process.

这是启动进程的可执行文件的绝对路径名。

Example:

例子:

/usr/local/bin/node

/usr/local/bin/node

#10


4  

How can a script tell whether it has been required as a commonjs module?

脚本如何判断它是否作为一个commonjs模块被要求?

Related: to check whether it has been required as a module vs run directly in node, you can check require.main !== module. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module

相关:要检查它是否作为模块在节点中直接运行时是否被要求,可以查看require。主要! = =模块。http://nodejs.org/docs/latest/api/modules.html accessing_the_main_module

#11


4  

Here's my variation on what's above:

以下是我对以上内容的变化:

(function(publish) {
    "use strict";

    function House(no) {
        this.no = no;
    };

    House.prototype.toString = function() {
        return "House #"+this.no;
    };

    publish(House);

})((typeof module == 'undefined' || (typeof window != 'undefined' && this == window))
    ? function(a) {this["House"] = a;}
    : function(a) {module.exports = a;});

To use it, you modify the "House" on the second last line to be whatever you want the name of the module to be in the browser and publish whatever you want the value of the module to be (usually a constructor or an object literal).

要使用它,您可以将最后一行上的“House”修改为您希望模块名称在浏览器中的任何内容,并发布您希望模块值为的任何内容(通常是构造函数或对象文字)。

In browsers the global object is window, and it has a reference to itself (there's a window.window which is == window). It seems to me that this is unlikely to occur unless you're in a browser or in an environment that wants you to believe you're in a browser. In all other cases, if there is a global 'module' variable declared, it uses that otherwise it uses the global object.

在浏览器中,全局对象是窗口,它有一个对自身的引用(有一个窗口)。是==窗口的窗口。在我看来,这是不可能发生的,除非你在浏览器或环境中,希望你相信你在浏览器中。在所有其他情况下,如果声明了全局“模块”变量,则使用它,否则使用全局对象。

#12


4  

I'm using process to check for node.js like so

我正在使用过程检查节点。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

记录在这里

#13


2  

Node.js has process object, so as long as You don't have any other script which create process You can use it to determine if code runs on Node.

节点。js有process对象,所以只要没有创建process的其他脚本,就可以使用它来确定代码是否在Node上运行。

var isOnNodeJs = false;
if(typeof process != "undefined") {
  isOnNodeJs = true;
}

if(isOnNodeJs){
  console.log("you are running under node.js");
}
else {
  console.log("you are NOT running under node.js");
}

#14


2  

This is a pretty safe and straight-forward way of assuring compatibility between server-side and client-side javascript, that will also work with browserify, RequireJS or CommonJS included client-side:

这是保证服务器端和客户端javascript之间兼容性的一种非常安全、直接的方法,也可以使用browserify、RequireJS或CommonJS包含的客户端:

(function(){

  // `this` now refers to `global` if we're in NodeJS
  // or `window` if we're in the browser.

}).call(function(){
  return (typeof module !== "undefined" &&
    module.exports &&
    typeof window === 'undefined') ?
    global : window;
}())

#15


1  

Edit: Regarding your updated question: "How can a script tell whether it has been required as a commonjs module?" I don't think it can. You can check whether exports is an object (if (typeof exports === "object")), since the spec requires that it be provided to modules, but all that tells you is that ... exports is an object. :-)

编辑:关于您更新后的问题:“脚本如何判断它是否作为一个commonjs模块被要求?”我认为它不能。您可以检查导出是否为对象(if (typeof exports === = "object")),因为规范要求将其提供给模块,但是告诉您的是……出口是一个对象。:-)


Original answer:

最初的回答:

I'm sure there's some NodeJS-specific symbol (EventEmitter, perhaps no, you have to use require to get the events module; see below) that you could check for, but as David said, ideally you're better off detecting the feature (rather than environment) if it makes any sense to do so.

我确定有一些特定于node的符号(EventEmitter,也许不是,您必须使用require来获取events模块;您可以检查一下,但是正如David所说,如果有必要的话,最好检测一下特性(而不是环境)。

Update: Perhaps something like:

更新:也许类似:

if (typeof require === "function"
    && typeof Buffer === "function"
    && typeof Buffer.byteLength === "function"
    && typeof Buffer.prototype !== "undefined"
    && typeof Buffer.prototype.write === "function") {

But that just tells you that you're in an environment with require and something very, very much like NodeJS's Buffer. :-)

但这只是告诉你,你处在一个有需求的环境中,一些非常非常非常类似NodeJS的缓冲区的东西。:-)

#16


-1  

Take the source of node.js and change it to define a variable like runningOnNodeJS. Check for that variable in your code.

以节点的来源为例。js并更改它来定义一个变量,比如runningOnNodeJS。在代码中检查该变量。

If you can't have your own private version of node.js, open a feature request in the project. Ask that they define a variable which gives you the version of node.js that you're running in. Then check for that variable.

如果您没有自己的节点私有版本。在项目中打开一个特性请求。要求他们定义一个变量,并给出节点的版本。你正在运行的js。然后检查这个变量。

#17


-1  

Very old post, but i just solved it by wrapping the require statements in a try - catch

非常古老的帖子,但是我只是通过在try - catch中包装require语句来解决它

    try {

           var fs = require('fs')

} catch(e) {
       alert('you are not in node !!!')
}

#1


71  

This is how the Underscore.js library does it (by looking for CommonJS support):

这就是下划线。js库(通过查找CommonJS支持):

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.

这里的示例保留了模块模式。

#2


68  

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.

没有可靠的方法来检测在节点中运行的情况。因为每个网站都可以很容易地声明相同的变量,但是,因为节点中没有窗口对象。默认情况下,你可以反过来检查你是否在浏览器中运行。

This is what I use for libs that should work both in a Browser and under Node.js:

这就是我对libs的使用,它应该在浏览器和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 good reason for someone do this, since you would explicitly need to leave out var or set the property on the global object.

如果在Node中定义了窗口,它可能仍然会爆炸。但是没有理由有人这样做,因为您需要显式地删除var或设置全局对象上的属性。

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 modules content in an anonymous funciton.

要检测您的脚本作为CommonJS模块是否必需,这同样不容易。commonJS只指定A:模块将通过调用函数require来包含,B:模块通过export对象上的属性导出。现在实现的方式留给底层系统。节点。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't go there by trying 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.

但是,不要通过一些疯狂的参数来检测它,而是使用上面的示例代码检查浏览器Node。js是一种更干净的环境,所以不太可能在那里声明窗口。

#3


25  

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

模块类型!== '未定义' && module。导出。

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函数时,它会将这个对象重置为一个空对象,并为您重新定义模块,这意味着您不必担心任何外部干扰。只要您的代码装载了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?

但是,这在浏览器上是行不通的,因为任何人都可以很容易地定义模块,使它看起来像是您正在寻找的对象。一方面,这可能是您想要的行为,但它也规定了库用户可以在全局范围中使用哪些变量。可能有人想要使用一个带有name模块的变量,该模块内部有导出供其他使用。这是不可能的,但是我们谁来判断其他人可以使用什么变量,仅仅因为另一个环境使用了那个变量名?

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:

但是,关键在于,如果我们假设您的脚本正在全局范围内加载(如果它是通过脚本标签加载的),那么不能在外部闭包中保留变量,因为浏览器不允许这样做。记住,在node中,这个对象是一个空对象,但是,模块变量仍然可用。这是因为它是在外部闭包中声明的。因此我们可以通过增加一个额外的检查来修复下划线的检查:

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.

有了这个,如果有人在浏览器的全局范围中声明模块,它将被放置在这个对象中,这会导致测试失败,因为这一点。模块,将与模块相同的对象。在节点,这个。模块不存在,模块存在于外部闭包中,因此测试将会成功,因为它们并不相等。

Thus, the final test is:

因此,最后的测试是:

typeof module !== 'undefined' && this.module !== module

= 'undefined' & this。模块! = =模块

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.

注意:虽然现在允许在全局范围内*使用模块变量,但仍有可能在浏览器中创建一个新的闭包和声明模块,然后在该闭包中加载脚本。此时,用户正在完全复制节点环境,并希望知道他们正在做什么,并尝试执行节点样式所需的操作。如果在脚本标记中调用代码,它仍然不会受到任何新的外部闭包的影响。

#4


21  

The following works in the browser unless intentionally,explicitly sabotaged:

以下在浏览器中工作,除非故意、明确地破坏:

if(typeof process === 'object' && process + '' === '[object process]'){
    // is node
}
else{
    // not node
}

Bam.

Bam。

#5


20  

I currently stumbled over a wrong detection of Node which is not aware of the Node-environment in Electron due to a misleading feature-detection. The following solutions identify the process-environment explicitly.

我最近偶然发现了一个错误的节点检测,由于一个错误的特性检测,它不知道电子中的节点环境。下面的解决方案明确地标识了流程环境。


Identify Node.js only

(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".

如果您正在一个节点进程中运行,这将会发现,因为进程。release包含“与当前[Node-]release相关的元数据”。

After the spawn of io.js the 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的衍生之后。进程.release.name的值也可能变成io。js(参见process-doc)。为了正确检测节点就绪的环境,我想你应该检查以下内容:

Identify Node (>= 3.0.0) or 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.

该语句使用节点5.5.0、电子0.36.9(节点5.1.1)和Chrome 48.0.2564.116进行测试。

Identify Node (>= 0.10.0) or 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.

注。我在这里张贴这个答案,因为这个问题把我带到了这里,尽管OP正在寻找另一个问题的答案。

#6


9  

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:

大多数提出的解决方案实际上都是可以伪造的。一种健壮的方法是使用object .prototype. tostring检查全局对象的内部类属性。内部类不能用JavaScript伪造:

var isNode = 
    typeof global !== "undefined" && 
    {}.toString.call(global) == '[object global]';

#7


9  

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.

有点偏执的对吧?通过检查更多的全局变量,您可以使它更加详细。

But DON'T!.

All these above can be faked/simulated anyway.

以上这些都可以伪造/模拟。

For example to fake the global object:

例如伪造全局对象:

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.

它不会连接到节点的原始全局对象,但会连接到浏览器中的窗口对象。它会暗示你在浏览器内的节点env。

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的全局变量时,就会发生这种情况。或者一些邪恶的开发人员以某种方式向我们的env注入代码。

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!

如果针对两个环境:浏览器和节点;“使用严格的”;或者简单地检查窗口或全局;并且在文档中清楚地表明您的代码只支持这些环境。就是这样!

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;
}

#8


8  

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”的自引用。这个自引用在节点中不存在。

  • In the browser 'this' is a reference to the global object, called 'window'.
  • 在浏览器中,“this”是对全局对象的引用,称为“窗口”。
  • In Node 'this' is a reference to the module.exports object.
    • 'this' is not a reference to the Node global object, called 'global'.
    • 'this'不是对节点全局对象的引用,称为'global'。
    • 'this' is not a reference to the the module variable declaration space.
    • 'this'不是对模块变量声明空间的引用。
  • 在Node 'this'是对模块的引用。出口对象。'this'不是对节点全局对象的引用,称为'global'。'this'不是对模块变量声明空间的引用。

To break the above suggested browser check you would have to do something like the following

要打破上面建议的浏览器检查,您需要做如下操作

this.window = this;

before executing the check.

在执行之前检查。

#9


4  

What about using the process object and checking execPath for node?

如何使用流程对象并检查节点的execPath ?

process.execPath

process.execPath

This is the absolute pathname of the executable that started the process.

这是启动进程的可执行文件的绝对路径名。

Example:

例子:

/usr/local/bin/node

/usr/local/bin/node

#10


4  

How can a script tell whether it has been required as a commonjs module?

脚本如何判断它是否作为一个commonjs模块被要求?

Related: to check whether it has been required as a module vs run directly in node, you can check require.main !== module. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module

相关:要检查它是否作为模块在节点中直接运行时是否被要求,可以查看require。主要! = =模块。http://nodejs.org/docs/latest/api/modules.html accessing_the_main_module

#11


4  

Here's my variation on what's above:

以下是我对以上内容的变化:

(function(publish) {
    "use strict";

    function House(no) {
        this.no = no;
    };

    House.prototype.toString = function() {
        return "House #"+this.no;
    };

    publish(House);

})((typeof module == 'undefined' || (typeof window != 'undefined' && this == window))
    ? function(a) {this["House"] = a;}
    : function(a) {module.exports = a;});

To use it, you modify the "House" on the second last line to be whatever you want the name of the module to be in the browser and publish whatever you want the value of the module to be (usually a constructor or an object literal).

要使用它,您可以将最后一行上的“House”修改为您希望模块名称在浏览器中的任何内容,并发布您希望模块值为的任何内容(通常是构造函数或对象文字)。

In browsers the global object is window, and it has a reference to itself (there's a window.window which is == window). It seems to me that this is unlikely to occur unless you're in a browser or in an environment that wants you to believe you're in a browser. In all other cases, if there is a global 'module' variable declared, it uses that otherwise it uses the global object.

在浏览器中,全局对象是窗口,它有一个对自身的引用(有一个窗口)。是==窗口的窗口。在我看来,这是不可能发生的,除非你在浏览器或环境中,希望你相信你在浏览器中。在所有其他情况下,如果声明了全局“模块”变量,则使用它,否则使用全局对象。

#12


4  

I'm using process to check for node.js like so

我正在使用过程检查节点。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

记录在这里

#13


2  

Node.js has process object, so as long as You don't have any other script which create process You can use it to determine if code runs on Node.

节点。js有process对象,所以只要没有创建process的其他脚本,就可以使用它来确定代码是否在Node上运行。

var isOnNodeJs = false;
if(typeof process != "undefined") {
  isOnNodeJs = true;
}

if(isOnNodeJs){
  console.log("you are running under node.js");
}
else {
  console.log("you are NOT running under node.js");
}

#14


2  

This is a pretty safe and straight-forward way of assuring compatibility between server-side and client-side javascript, that will also work with browserify, RequireJS or CommonJS included client-side:

这是保证服务器端和客户端javascript之间兼容性的一种非常安全、直接的方法,也可以使用browserify、RequireJS或CommonJS包含的客户端:

(function(){

  // `this` now refers to `global` if we're in NodeJS
  // or `window` if we're in the browser.

}).call(function(){
  return (typeof module !== "undefined" &&
    module.exports &&
    typeof window === 'undefined') ?
    global : window;
}())

#15


1  

Edit: Regarding your updated question: "How can a script tell whether it has been required as a commonjs module?" I don't think it can. You can check whether exports is an object (if (typeof exports === "object")), since the spec requires that it be provided to modules, but all that tells you is that ... exports is an object. :-)

编辑:关于您更新后的问题:“脚本如何判断它是否作为一个commonjs模块被要求?”我认为它不能。您可以检查导出是否为对象(if (typeof exports === = "object")),因为规范要求将其提供给模块,但是告诉您的是……出口是一个对象。:-)


Original answer:

最初的回答:

I'm sure there's some NodeJS-specific symbol (EventEmitter, perhaps no, you have to use require to get the events module; see below) that you could check for, but as David said, ideally you're better off detecting the feature (rather than environment) if it makes any sense to do so.

我确定有一些特定于node的符号(EventEmitter,也许不是,您必须使用require来获取events模块;您可以检查一下,但是正如David所说,如果有必要的话,最好检测一下特性(而不是环境)。

Update: Perhaps something like:

更新:也许类似:

if (typeof require === "function"
    && typeof Buffer === "function"
    && typeof Buffer.byteLength === "function"
    && typeof Buffer.prototype !== "undefined"
    && typeof Buffer.prototype.write === "function") {

But that just tells you that you're in an environment with require and something very, very much like NodeJS's Buffer. :-)

但这只是告诉你,你处在一个有需求的环境中,一些非常非常非常类似NodeJS的缓冲区的东西。:-)

#16


-1  

Take the source of node.js and change it to define a variable like runningOnNodeJS. Check for that variable in your code.

以节点的来源为例。js并更改它来定义一个变量,比如runningOnNodeJS。在代码中检查该变量。

If you can't have your own private version of node.js, open a feature request in the project. Ask that they define a variable which gives you the version of node.js that you're running in. Then check for that variable.

如果您没有自己的节点私有版本。在项目中打开一个特性请求。要求他们定义一个变量,并给出节点的版本。你正在运行的js。然后检查这个变量。

#17


-1  

Very old post, but i just solved it by wrapping the require statements in a try - catch

非常古老的帖子,但是我只是通过在try - catch中包装require语句来解决它

    try {

           var fs = require('fs')

} catch(e) {
       alert('you are not in node !!!')
}