173

Node.jsスクリプトから必要なスクリプトがあり、JavaScriptエンジンを独立させたいと考えています。

たとえば、exports.x = y;Node.jsで実行されている場合にのみ実行したいと思います。このテストを実行するにはどうすればよいですか?


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

私が挙げた特定の例では、より正確な質問は次のようになります。

スクリプトは、CommonJSモジュールとして必要かどうかをどのように判断できますか?

4

22 に答える 22

116

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

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

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

} else {
    window.foo = {};
}

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

編集

スクリプトが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そこで宣言される可能性はほとんどありません。

于 2010-11-19T11:51:17.077 に答える
83

CommonJSサポートを探すことによりUnderscore.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._ = _;
    }
})();

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

于 2011-03-04T17:34:12.817 に答える
51

私は現在、誤解を招く機能検出のために、Electronのノード環境を認識していないノードの誤った検出に遭遇しました。次のソリューションは、プロセス環境を明示的に識別します。


Node.jsのみを特定する

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

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

io.jsの生成後、の値process.release.nameも次のようになる場合がありますio.jsprocess-docを参照)。ノード対応環境を適切に検出するには、次のように確認する必要があると思います。

ノード(> = 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を使用)、およびChrome48.0.2564.116でテストされました。

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

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

@daluegeのコメントは、より一般的な証拠について考えるように私を刺激しました。これは、Node.js>= 0.10から機能するはずです。以前のバージョンの一意の識別子が見つかりませんでした。


追伸:OPは別の質問への回答を探していましたが、質問が私をここに導いたので、私はその回答をここに投稿しています。

于 2016-03-05T10:46:24.933 に答える
26

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

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

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

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し、そのクロージャ内でスクリプトを読み込むことで、ブラウザでこれをバイパスすることができます。その時点で、ユーザーはノード環境を完全に複製しており、うまくいけば、ユーザーが何をしているかを理解しており、必要なノードスタイルを実行しようとしています。コードがスクリプトタグで呼び出された場合でも、新しい外部クロージャから安全になります。

于 2012-08-11T23:06:41.177 に答える
22

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

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

バム。

于 2014-06-18T07:34:14.083 に答える
18

これを行うためのかなりクールな方法もあります:

const isBrowser = this.window === this;

これが機能するのは、ブラウザでは、グローバルな「this」変数に「window」と呼ばれる自己参照があるためです。この自己参照はノードに存在しません。

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

上記の提案されたブラウザチェックを破るには、次のようなことをする必要があります

this.window = this;

チェックを実行する前に。

于 2017-01-25T23:21:01.600 に答える
14

さらに別の環境検出

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

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

少しパラノイアでしょ?より多くのグローバルをチェックすることで、これをより冗長にすることができます。

しかし、しないでください!。

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

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

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

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

人生は短いです!

私たちの環境が偽造されているかどうかは気になりますか?これは、愚かな開発者がグローバルスコープで呼び出されるグローバル変数を宣言したときに発生しglobalます。または、いくつかの邪悪な開発者がどういうわけか私たちの環境にコードを挿入します。

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

だから何?

2つの環境を対象とする場合:ブラウザとノード。
"use strict"; または単にチェックするwindowglobal; また、ドキュメントで、コードがこれらの環境のみをサポートしていることを明確に示します。それでおしまい!

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;
}
于 2016-08-07T15:38:54.517 に答える
9

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

var isNode = 
    typeof global !== "undefined" && 
    {}.toString.call(global) == '[object global]';
于 2013-08-05T11:53:42.190 に答える
6

この記事の執筆時点では、JavaScriptの非常に新しい機能を活用しているため、この回答は「近日公開」のオプションに近いものです。

const runtime = globalThis.process?.release?.name || 'not node'
console.log(runtime)

runtime値はまたはのいずれnodeかになりますnot node

前述のように、これはいくつかの新しいJavaScript機能に依存しています。globalThisECMAScript2020仕様の最終的な機能です。オプションの連鎖/nullish合体(の?一部globalThis.process?.release?.name)は、Chrome 80に同梱されているV8エンジンでサポートされています。2020年4月8日以降、このコードはブラウザで機能しますが、ノード13ブランチが使用するためノードでは機能しません。 V87.9.xxx。ノード14(2020年4月21日にリリース予定)はV88.x+を使用することになっていると思います。

このアプローチには、現在の制限が適切に適用されています。でも; ブラウザ/ノードがリリースされるペースで、最終的には信頼できるワンライナーになります。

于 2020-04-08T22:22:58.787 に答える
4

プロセスオブジェクトを使用してexecPathをチェックするのはnodeどうですか?

process.execPath

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

例:

/ usr / local / bin / node

于 2010-11-21T14:14:02.660 に答える
4

スクリプトは、commonjsモジュールとして必要かどうかをどのように判断できますか?

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

于 2011-12-05T17:04:41.437 に答える
4

上記のバリエーションは次のとおりです。

(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.windowがあります)。ブラウザを使用している場合、またはブラウザを使用していると信じてほしい環境にいる場合を除いて、これが発生する可能性は低いように思われます。他のすべての場合、宣言されたグローバル'モジュール'変数がある場合はそれを使用し、そうでない場合はグローバルオブジェクトを使用します。

于 2012-04-13T13:27:45.837 に答える
4

私はprocessそのようにnode.jsをチェックするために使用しています

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
}

ここに文書化

于 2013-04-04T14:14:26.033 に答える
2

これは、サーバー側とクライアント側の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;
}())
于 2014-07-31T16:02:58.540 に答える
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");
}
于 2015-01-13T20:33:33.660 に答える
1

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


元の答え:

確認できるNodeJS固有のシンボル(EventEmitterおそらく、イベントモジュールを取得 するために使用する必要がrequireあります。以下を参照)があると確信していますが、Davidが言ったように、理想的には機能を検出する方が良いでしょう(むしろ環境よりも)そうすることが理にかなっている場合。

更新:おそらく次のようなものです:

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

しかし、それはあなたがrequireNodeJSのような環境にいることを示していますBuffer。:-)

于 2010-11-19T11:47:01.957 に答える
1
const isNode =
  typeof process !== 'undefined' &&
  process.versions != null &&
  process.versions.node != null;
于 2019-07-30T17:56:56.600 に答える
1

デバッグパッケージのソースから:

const isBrowser = typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs

https://github.com/visionmedia/debug/blob/master/src/index.js#L6

于 2019-10-04T15:13:57.280 に答える
0

非常に古い投稿ですが、requireステートメントをtry-catchでラップすることで解決しました

try {
     var fs = require('fs')
} catch(e) {
     alert('you are not in node !!!')
}
于 2014-07-24T20:32:51.180 に答える
0

Node.jsを具体的にチェックしたかったので、これはあなたの質問に直接答えることはありませんが、次のように言うのに十分役立ちます。

ほとんどの場合、ブラウザとサーバー側のJavaScriptを区別したいだけであれば、ドキュメントの存在を確認するだけで十分です。

if (typeof document !== 'undefined') {} // do stuff

// This one is overkill, but 100% always works:
if (typeof window !== 'undefined' && window && window.window === window) {
   if (typeof window.document !== 'undefined' && document.documentElement) {

   }
}
于 2020-10-20T13:35:51.123 に答える
0

非常に古い投稿ですが、他の回答を組み合わせて解決しました。

var isNode=()=>!("undefined"!=typeof window||"object"!=typeof module||!module.exports||"object"!=typeof process||!process.moduleLoadList);
console.log(isNode()); //=> false

于 2021-03-27T05:31:53.873 に答える
-1

node.jsのソースを取得し、それを変更して。のような変数を定義しますrunningOnNodeJS。コードでその変数を確認してください。

node.jsの独自のプライベートバージョンを使用できない場合は、プロジェクトで機能リクエストを開きます。実行しているnode.jsのバージョンを提供する変数を定義するように依頼します。次に、その変数を確認します。

于 2010-11-19T12:35:12.907 に答える