Node.jsスクリプトから必要なスクリプトがあり、javascriptエンジンを独立させたい。
だから、例えば、私はやりたい:
exports.x = y;
node.jsで実行されている場合のみ。このテストを実行するにはどうすればよいですか?
Edit:この質問を投稿するとき、node.jsモジュール機能が commonjs に基づいていることを知りませんでした。
具体的な例については、もっと正確な質問をしたでしょう:
Commonjsモジュールとして必要かどうかをスクリプトで確認するにはどうすればよいですか?
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._ = _;
}
})();
ここの例では、モジュールパターンを保持しています。
すべてのウェブサイトが同じ変数を簡単に宣言できるため、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
がそこで宣言されることはまずありません。
私は現在、 Electron のNode-environmentを認識していないnotであるNodeの誤った検出につまずいた=誤解を招く機能検出のため。以下のソリューションは、プロセス環境を明示的に識別します。
(typeof process !== 'undefined') && (process.release.name === 'node')
process.release
には「現在の[Node-] releaseに関連するメタデータ」が含まれているため、Nodeプロセスで実行されているかどうかがわかります。
io.js の生成後、process.release.name
の値もio.js
になる場合があります( process-doc を参照)。 Node対応環境を適切に検出するには、次のようにチェックする必要があります。
(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でテストされました。
(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')
@daluegeのコメントは、より一般的な証拠について考えるきっかけになりました。これはNode.js> = .1 から動作するはずです。以前のバージョンの一意の識別子が見つかりませんでした。
P.s .:質問が私をここに導くので、私はその答えをここに投稿していますが、OPは別の質問に対する答えを探していました。
コードが実行されている環境を把握しようとする際の問題は、どのオブジェクトも変更および宣言できるため、どのオブジェクトが環境にネイティブで、どのオブジェクトがプログラムによって変更されたかを把握することがほぼ不可能になることです。
ただし、どの環境にいるかを確認するために使用できるトリックがいくつかあります。
アンダースコアライブラリで使用されている一般に受け入れられているソリューションから始めましょう。
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
を宣言してから、そのクロージャ内のスクリプト。その時点で、ユーザーはノード環境を完全に複製しており、できれば自分が何をしているかを知っており、ノードスタイルの要件を実行しようとしています。スクリプトタグ内でコードが呼び出された場合でも、新しい外部クロージャーに対して安全です。
以下は、意図的に明示的に妨害されない限り、ブラウザで機能します。
if(typeof process === 'object' && process + '' === '[object process]'){
// is node
}
else{
// not node
}
バム。
同様にそれを行う非常にクールな方法は次のとおりです。
const isBrowser = this.window === this;
これは、ブラウザではグローバルな「this」変数が「window」という自己参照を持っているためです。この自己参照はNodeには存在しません。
上記の推奨ブラウザチェックを破るには、次のようなことをする必要があります。
this.window = this;
チェックを実行する前。
さらに別の環境検出:
(意味:ここでの答えのほとんどは大丈夫です。)
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;
}
提案されたソリューションのほとんどは実際に偽造することができます。堅牢な方法は、 Object.prototype.toString
を使用して、グローバルオブジェクトの内部Class
プロパティを確認することです。 JavaScriptで内部クラスを偽造することはできません。
var isNode =
typeof global !== "undefined" &&
{}.toString.call(global) == '[object global]';
上記のものに対する私のバリエーションは次のとおりです。
(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があります)。あなたがブラウザを使用しているか、ブラウザを使用していると信じてほしい環境にいる場合を除き、これは起こりそうにないようです。他のすべてのケースでは、グローバルな「モジュール」変数が宣言されている場合、それを使用します。そうでない場合は、グローバルオブジェクトを使用します。
Commonjsモジュールとして必要かどうかをスクリプトで確認するにはどうすればよいですか?
関連:モジュールとして必要であるか、ノードで直接実行するかを確認するには、require.main !== module
を確認できます。 http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module
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
}
文書化 ここ
プロセスオブジェクトの使用とnode
の- execPath のチェックはどうですか?
process.execPath
これは、プロセスを開始した実行可能ファイルの絶対パス名です。
例:
/ usr/local/bin/node
これは、サーバー側とクライアント側の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;
}())
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");
}
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
に非常によく似た何かがある環境にいることを伝えるだけです。 :-)
const isNode =
typeof process !== 'undefined' &&
process.versions != null &&
process.versions.node != null;
とてもシンプルだと思います。
if (process && process.title === 'node') {
// Your code here
}