web-dev-qa-db-ja.com

node.jsでスクリプトが実行されているかどうかを確認する方法は?

Node.jsスクリプトから必要なスクリプトがあり、javascriptエンジンを独立させたい。

だから、例えば、私はやりたい:

exports.x = y;

node.jsで実行されている場合のみ。このテストを実行するにはどうすればよいですか?

Edit:この質問を投稿するとき、node.jsモジュール機能が commonjs に基づいていることを知りませんでした。

具体的な例については、もっと正確な質問をしたでしょう:

Commonjsモジュールとして必要かどうかをスクリプトで確認するにはどうすればよいですか?

143
theosp

CommonJSサポートを探すことにより、これは nderscore.js ライブラリが行う方法です:

編集:更新された質問へ:

(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._ = _;
    }
})();

ここの例では、モジュールパターンを保持しています。

76
Ross

すべてのウェブサイトが同じ変数を簡単に宣言できるため、Node.jsでの実行を検出する信頼性の高い方法はありませんが、デフォルトではNode.jsにwindowオブジェクトがないため、逆方向に移動して内部で実行しているかどうかを確認できますブラウザ。

これは、ブラウザとNode.jsの両方で動作するライブラリに使用するものです。

if (typeof window === 'undefined') {
    exports.foo = {};

} else {
    window.foo = {};
}

windowがNode.jsで定義されている場合でも爆発する可能性がありますが、明示的にvarを省くか、プロパティを設定する必要があるため、誰かがこれを行う理由はありませんgood理由はありませんglobalオブジェクト。

編集

スクリプトがCommonJSモジュールとして必要かどうかを検出するために、これも簡単ではありません。 commonJSが指定しているのは、A:モジュールは関数requireへの呼び出しを介して含まれ、B:モジュールはexportsオブジェクトのプロパティを介して物をエクスポートするということだけです。実装方法は、基礎となるシステムに任されています。 Node.jsは、モジュールのコンテンツを匿名関数でラップします。

function (exports, require, module, __filename, __dirname) { 

参照: https://github.com/ry/node/blob/master/src/node.js#L325

しかし、してはいけないいくつかのクレイジーなarguments.callee.toString()のものを介してそれを検出しようとし、代わりにブラウザをチェックする上記の私のサンプルコードを使用してください。 Node.jsは非常にクリーンな環境なので、windowがそこで宣言されることはまずありません。

90
Ivo Wetzel

私は現在、 Electron のNode-environmentを認識していないnotであるNodeの誤った検出につまずいた=誤解を招く機能検出のため。以下のソリューションは、プロセス環境を明示的に識別します。


Node.jsのみを識別する

(typeof process !== 'undefined') && (process.release.name === 'node')

process.release には「現在の[Node-] releaseに関連するメタデータ」が含まれているため、Nodeプロセスで実行されているかどうかがわかります。

io.js の生成後、process.release.nameの値もio.jsになる場合があります( process-doc を参照)。 Node対応環境を適切に検出するには、次のようにチェックする必要があります。

Node(> = 3.0.0)またはio.jsを識別します

(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)

このステートメントは、Node 5.5.0、Electron 0.36.9(Node 5.1.1)およびChrome 48.0.2564.116でテストされました。

Node(> = 0.10.0)またはio.jsを識別します

(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')

@daluegeのコメントは、より一般的な証拠について考えるきっかけになりました。これはNode.js> = .1 から動作するはずです。以前のバージョンの一意の識別子が見つかりませんでした。


P.s .:質問が私をここに導くので、私はその答えをここに投稿していますが、OPは別の質問に対する答えを探していました。

32
Florian Breisch

コードが実行されている環境を把握しようとする際の問題は、どのオブジェクトも変更および宣言できるため、どのオブジェクトが環境にネイティブで、どのオブジェクトがプログラムによって変更されたかを把握することがほぼ不可能になることです。

ただし、どの環境にいるかを確認するために使用できるトリックがいくつかあります。

アンダースコアライブラリで使用されている一般に受け入れられているソリューションから始めましょう。

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

この手法は、require関数が呼び出されると、thisオブジェクトを空のオブジェクトにリセットし、moduleを再定義するため、サーバー側にとって実際に完全に適切です。外部からの改ざんを心配する必要はありません。コードがrequireでロードされている限り、安全です。

しかし、誰でも簡単にmoduleを定義して、探しているオブジェクトのように見せることができるため、これはブラウザ上でばらばらになります。一方で、これは望みの動作かもしれませんが、ライブラリユーザーがグローバルスコープで使用できる変数も決定します。誰かがmoduleという名前の変数を使用して、その中にexportsを入れて別の用途に使用したい場合があります。可能性は低いですが、他の環境がその変数名を使用しているという理由だけで、他の誰かが使用できる変数を判断するのは誰ですか?

ただし、トリックは、スクリプトがグローバルスコープに読み込まれていると想定している場合(スクリプトタグを介して読み込まれている場合)、外部のクロージャーで変数を予約できないためです。 。ノードでは、thisオブジェクトは空のオブジェクトですが、module変数はまだ使用可能です。それは外側のクロージャーで宣言されているからです。したがって、追加のチェックを追加することで、アンダースコアのチェックを修正できます。

this.module !== module

これにより、誰かがブラウザのグローバルスコープでmoduleを宣言すると、thisオブジェクトに配置され、this.moduleがモジュールと同じオブジェクト。ノードでは、this.moduleは存在せず、moduleは外部クロージャー内に存在するため、同等ではないため、テストは成功します。

したがって、最終テストは次のとおりです。

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

注:これにより、グローバルスコープでmodule変数を自由に使用できるようになりましたが、新しいクロージャーを作成し、その中にmoduleを宣言してから、そのクロージャ内のスクリプト。その時点で、ユーザーはノード環境を完全に複製しており、できれば自分が何をしているかを知っており、ノードスタイルの要件を実行しようとしています。スクリプトタグ内でコードが呼び出された場合でも、新しい外部クロージャーに対して安全です。

25
TimE

以下は、意図的に明示的に妨害されない限り、ブラウザで機能します。

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

バム。

20
user3751385

同様にそれを行う非常にクールな方法は次のとおりです。

const isBrowser = this.window === this;

これは、ブラウザではグローバルな「this」変数が「window」という自己参照を持っているためです。この自己参照はNodeには存在しません。

  • ブラウザでは、「this」は「window」と呼ばれるグローバルオブジェクトへの参照です。
  • Nodeでは、「this」はmodule.exportsオブジェクトへの参照です。
    • 'this'はnot 'global'と呼ばれるNodeグローバルオブジェクトへの参照です。
    • 'this'はnotモジュール変数宣言スペースへの参照です。

上記の推奨ブラウザチェックを破るには、次のようなことをする必要があります。

this.window = this;

チェックを実行する前。

13
Patrick

さらに別の環境検出

(意味:ここでの答えのほとんどは大丈夫です。)

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 ?..
}

少し妄想的でしょ?より多くの globals をチェックすることで、これをより冗長にすることができます。

しかし、いけない!.

とにかく上記のすべてを偽造/シミュレートできます。

たとえば、globalオブジェクトを偽造するには:

global = {
    toString: function () {
        return '[object global]';
    },
    GLOBAL: global,
    setImmediate: function (a, b, c, d) {}
 };
 setImmediate = function (a, b, c, d) {};
 ...

これは、ノードの元のグローバルオブジェクトにアタッチされませんが、ブラウザのwindowオブジェクトにアタッチされます。したがって、ブラウザ内のNode envにいることを意味します。

人生は短いです!

環境が偽造されているかどうか気にしますか?愚かな開発者がグローバルスコープでglobalというグローバル変数を宣言すると発生します。または、悪の開発者がなんらかの方法でenvにコードを挿入します。

これをキャッチするとコードの実行を妨げる可能性がありますが、アプリの他の多くの依存関係がこれに巻き込まれる可能性があります。そのため、最終的にコードが壊れます。コードが十分に優れている場合は、他の人が行った可能性のある愚かな誤りをすべて気にするべきではありません。

だから何?

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]';

可能であれば、ユースケース;環境検出の代わり。 try/catchブロック内で同期機能検出を行います。 (これらの実行には数ミリ秒かかります)。

例えば.

function isPromiseSupported() {
    var supported = false;
    try {
        var p = new Promise(function (res, rej) {});
        supported = true;
    } catch (e) {}
    return supported;
}
10

提案されたソリューションのほとんどは実際に偽造することができます。堅牢な方法は、 Object.prototype.toString を使用して、グローバルオブジェクトの内部Classプロパティを確認することです。 JavaScriptで内部クラスを偽造することはできません。

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

上記のものに対する私のバリエーションは次のとおりです。

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

それを使用するには、最後の2行目の「House」をブラウザでモジュールの名前にしたいものに変更し、モジュールの値にしたいもの(通常はコンストラクタまたはオブジェクトリテラル)を公開します)。

ブラウザでは、グローバルオブジェクトはウィンドウであり、それ自体への参照を持っています(== windowであるwindow.windowがあります)。あなたがブラウザを使用しているか、ブラウザを使用していると信じてほしい環境にいる場合を除き、これは起こりそうにないようです。他のすべてのケースでは、グローバルな「モジュール」変数が宣言されている場合、それを使用します。そうでない場合は、グローバルオブジェクトを使用します。

4
kybernetikos

Commonjsモジュールとして必要かどうかをスクリプトで確認するにはどうすればよいですか?

関連:モジュールとして必要であるか、ノードで直接実行するかを確認するには、require.main !== moduleを確認できます。 http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module

4
Pete

Node.jsを確認するためにprocessを使用しています

if (typeof(process) !== 'undefined' && process.version === 'v0.9.9') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

または

if (typeof(process) !== 'undefined' && process.title === 'node') {
  console.log('You are running Node.js');
} else {
  // check for browser
}

文書化 ここ

4
Chris

プロセスオブジェクトの使用とnodeの-​​ execPath のチェックはどうですか?

process.execPath

これは、プロセスを開始した実行可能ファイルの絶対パス名です。

例:

/ usr/local/bin/node

4
Kevin Hakanson

これは、サーバー側とクライアント側の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;
}())
2

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");
}
2

Edit:更新された質問について: "commonjsモジュールとして必要かどうかをスクリプトはどのように判断できますか?"私はそれができるとは思わない。 仕様 はモジュールに提供する必要があるため、exportsがオブジェクト(if (typeof exports === "object"))であるかどうかを確認できますが、それは... exportsはオブジェクトです。 :-)


元の回答:

NodeJS固有のシンボル(EventEmitter、おそらく いいえ、イベントモジュールを取得するにはrequireを使用する必要があります。以下を参照してください)が、デビッドが言ったように、理想的には、それが意味をなすのであれば、(環境ではなく)機能を検出する方が良いでしょう。

Update:おそらく次のようなもの:

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

しかし、それは、あなたがrequireとNodeJSのBufferに非常によく似た何かがある環境にいることを伝えるだけです。 :-)

1
T.J. Crowder
const isNode =
  typeof process !== 'undefined' &&
  process.versions != null &&
  process.versions.node != null;
0
BAR

とてもシンプルだと思います。

     if (process && process.title === 'node') {
        // Your code here
     }
0
Raheel Riaz