J'ai un script dont j'ai besoin d'un script node.js, que je veux garder indépendant du moteur javascript.
Donc, par exemple, je veux faire:
exports.x = y;
seulement s'il fonctionne sous node.js. Comment puis-je effectuer ce test?
Edit: Lors de la publication de cette question, je ne savais pas que la fonctionnalité des modules de node.js était basée sur commonjs .
Pour l'exemple spécifique, j'ai donné une question plus précise aurait été:
Comment un script peut-il indiquer s'il a été requis en tant que module commonjs?
En recherchant le support CommonJS, voici comment la bibliothèque Underscore.js le fait:
Modifier: à votre question mise à jour:
(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._ = _;
}
})();
Exemple ici conserve le modèle de module.
Il n’existe aucun moyen fiable de détecter l’exécution dans Node.js car chaque site Web peut facilement déclarer les mêmes variables, mais comme il n’existe pas d’objet window
dans Node.js par défaut, vous pouvez vérifier l’inverse et vérifier si vous utilisez l’intérieur. un navigateur.
C'est ce que j'utilise pour les bibliothèques qui doivent fonctionner à la fois dans un navigateur et sous Node.js:
if (typeof window === 'undefined') {
exports.foo = {};
} else {
window.foo = {};
}
Il peut encore exploser si window
est défini dans Node.js mais il n'y a pas de bonne raison de le faire, car vous auriez explicitement besoin de laisser var
ou de définir la propriété sur l'objet global
.
MODIFIER
Pour détecter si votre script a été requis en tant que module CommonJS, ce n'est pas facile à nouveau. La seule chose que commonJS spécifie est que A: Les modules seront inclus via un appel à la fonction require
et B: Les modules exportent des choses via des propriétés de l’objet exports
. Maintenant, la manière dont cela est mis en œuvre est laissée au système sous-jacent. Node.js encapsule le contenu des modules dans une fonction anonyme.
function (exports, require, module, __filename, __dirname) {
Voir: https://github.com/ry/node/blob/master/src/node.js#L325
Mais ne pas y aller en essayant de détecter cela via des trucs fous arguments.callee.toString()
, utilisez plutôt mon exemple de code ci-dessus qui vérifie le navigateur, Node.js est un environnement plus propre, il est donc peu probable que window
soit déclaré Là.
Je suis actuellement tombé sur une détection erronée de Node qui est pas consciente de l'environnement Node dans Electron en raison d'une détection de fonctionnalité trompeuse. Les solutions suivantes identifient explicitement l'environnement de processus.
(typeof process !== 'undefined') && (process.release.name === 'node')
Cela permettra de savoir si vous utilisez un processus de nœud, car process.release
contient les "métadonnées liées à la version actuelle [de nœud]".
Après l'apparition de io.js , la valeur de process.release.name
peut également devenir io.js
(voir le process-doc ). Pour détecter correctement un environnement prêt pour les nœuds, vous devriez vérifier les points suivants:
(typeof process !== 'undefined') &&
(process.release.name.search(/node|io.js/) !== -1)
Cette instruction a été testée avec les nœuds 5.5.0, Electron 0.36.9 (avec le nœud 5.1.1) et Chrome 48.0.2564.116.
(typeof process !== 'undefined') &&
(typeof process.versions.node !== 'undefined')
Le commentaire de @ daluege m'a incité à réfléchir à une preuve plus générale. Cela devrait fonctionner à partir de Node.js> = 0.10 . Je n'ai pas trouvé d'identifiant unique pour les versions précédentes.
P.s .: Je publie cette réponse ici puisque la question m'amène ici, même si le PO cherchait une réponse à une question différente.
Le problème pour essayer de comprendre l'environnement dans lequel votre code est exécuté est que tout objet peut être modifié et déclaré, ce qui rend presque impossible de déterminer quels objets sont natifs de l'environnement et lesquels ont été modifiés par le programme.
Cependant, il existe quelques astuces que nous pouvons utiliser pour déterminer avec certitude dans quel environnement vous vous trouvez.
Commençons par la solution généralement acceptée utilisée dans la bibliothèque de soulignement:
typeof module !== 'undefined' && module.exports
Cette technique convient parfaitement au serveur, car lorsque la fonction require
est appelée, elle réinitialise l’objet this
en un objet vide et redéfinit à nouveau module
, ce qui signifie que vous n’aurez plus à vous soucier de toute modification externe. Tant que votre code est chargé avec require
, vous êtes en sécurité.
Cependant, cela s’efface dans le navigateur, tout le monde pouvant facilement définir module
pour donner l’impression que c’est l’objet que vous recherchez. D'une part, cela peut correspondre au comportement souhaité, mais il dicte également les variables que l'utilisateur de bibliothèque peut utiliser dans l'étendue globale. Peut-être que quelqu'un veut utiliser une variable avec le nom module
qui a exports
à l'intérieur pour une autre utilisation. C'est peu probable, mais qui sommes-nous pour juger des variables que quelqu'un d'autre peut utiliser, simplement parce qu'un autre environnement utilise ce nom de variable?
Le truc, cependant, est que si nous supposons que votre script est chargé dans la portée globale (ce qui le sera s'il est chargé via une balise script), une variable ne peut pas être réservée dans une fermeture externe, car le navigateur ne le permet pas. . Rappelez-vous maintenant dans le noeud que l’objet this
est un objet vide, mais que la variable module
est toujours disponible. C'est parce qu'il est déclaré dans une fermeture extérieure. Nous pouvons donc corriger le chèque de soulignement en ajoutant un chèque supplémentaire:
this.module !== module
Avec cela, si quelqu'un déclare module
dans la portée globale du navigateur, il sera placé dans l'objet this
, ce qui entraînera l'échec du test car this.module
sera le même objet que module. Sur le noeud, this.module
n'existe pas et module
existe dans une fermeture externe. Le test réussira donc, car ils ne sont pas équivalents.
Ainsi, le test final est:
typeof module !== 'undefined' && this.module !== module
Remarque: Bien que cela permette maintenant à la variable module
d'être utilisée librement dans l'étendue globale, il est toujours possible de l'ignorer sur le navigateur en créant une nouvelle fermeture et en déclarant module
dans celle-ci, puis en chargeant le script dans cette fermeture. À ce stade, l'utilisateur réplique entièrement l'environnement du nœud et, espérons-le, sait ce qu'il fait et tente de créer un style de nœud requis. Si le code est appelé dans une balise de script, il sera toujours à l'abri de toute nouvelle fermeture externe.
Ce qui suit fonctionne dans le navigateur, sauf s'il est intentionnellement explicitement saboté:
if(typeof process === 'object' && process + '' === '[object process]'){
// is node
}
else{
// not node
}
Bam.
Voici une façon plutôt cool de le faire aussi:
const isBrowser = this.window === this;
Cela fonctionne car dans les navigateurs, la variable globale 'this' a une référence propre appelée 'fenêtre'. Cette référence de soi n'existe pas dans Node.
Pour rompre la vérification du navigateur suggérée ci-dessus, vous devez procéder comme suit:
this.window = this;
avant d'exécuter le contrôle.
Encore un autre environnement de détection:
(Signification: la plupart des réponses ici sont correctes.)} _
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 ?..
}
Un peu paranoïaque non? Vous pouvez rendre ceci plus verbeux en vérifiant plus globals .
Tous ceux ci-dessus peuvent être falsifiés/simulés de toute façon.
Par exemple, pour simuler l'objet global
:
global = {
toString: function () {
return '[object global]';
},
GLOBAL: global,
setImmediate: function (a, b, c, d) {}
};
setImmediate = function (a, b, c, d) {};
...
Cela ne sera pas attaché à l'objet global d'origine du nœud, mais il sera attaché à l'objet window
dans un navigateur. Donc, cela signifie que vous êtes dans l'environnement Node dans un navigateur.
Est-ce que nous nous soucions si notre environnement est falsifié? Cela se produirait lorsqu'un développeur stupide déclarerait une variable globale appelée global
dans la portée globale. Ou bien, un mauvais développeur injecte du code dans notre env.
Nous pouvons empêcher notre code de s'exécuter lorsque nous détectons cela, mais de nombreuses autres dépendances de notre application pourraient être prises au piège. Donc, finalement, le code va casser. Si votre code est assez bon, vous ne devriez pas vous soucier de chaque erreur stupide qui aurait pu être commise par d'autres.
Si vous ciblez 2 environnements: Navigateur et Nœud;"use strict"
; et soit simplement cocher window
ou global
; et indiquez clairement que, dans la documentation, votre code ne prend en charge que ces environnements. C'est tout!
var isBrowser = typeof window !== 'undefined'
&& ({}).toString.call(window) === '[object Window]';
var isNode = typeof global !== "undefined"
&& ({}).toString.call(global) === '[object global]';
Si possible pour votre cas d'utilisation; au lieu de la détection de l'environnement; faire la détection de fonctionnalité synchrone dans un bloc try/catch. (Cela prendra quelques millisecondes à exécuter).
par exemple.
function isPromiseSupported() {
var supported = false;
try {
var p = new Promise(function (res, rej) {});
supported = true;
} catch (e) {}
return supported;
}
La plupart des solutions proposées peuvent en réalité être faussées. Une méthode robuste consiste à vérifier la propriété interne Class
de l'objet global à l'aide de Object.prototype.toString
. La classe interne ne peut pas être falsifiée en JavaScript:
var isNode =
typeof global !== "undefined" &&
{}.toString.call(global) == '[object global]';
Voici ma variation sur ce qui précède:
(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;});
Pour l'utiliser, vous modifiez la "Maison" sur l'avant dernière ligne pour que vous vouliez que le nom du module apparaisse dans le navigateur, puis vous publiez ce que vous voulez pour la valeur du module ).
Dans les navigateurs, l'objet global est window et il a une référence à lui-même (il y a un window.window qui est == window). Il me semble que cela ne se produira que si vous êtes dans un navigateur ou dans un environnement qui vous fait croire que vous êtes dans un navigateur. Dans tous les autres cas, s'il existe une variable globale 'module' déclarée, elle utilise sinon l'objet global.
Comment un script peut-il indiquer s'il a été requis en tant que module commonjs?
En relation: pour vérifier s'il a été requis en tant que module vs exécuté directement dans le noeud, vous pouvez vérifier require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_module
J'utilise process
pour vérifier node.js comme si
if (typeof(process) !== 'undefined' && process.version === 'v0.9.9') {
console.log('You are running Node.js');
} else {
// check for browser
}
ou
if (typeof(process) !== 'undefined' && process.title === 'node') {
console.log('You are running Node.js');
} else {
// check for browser
}
Documenté ici
Qu'en est-il d'utiliser l'objet de processus et de vérifier execPath for node
?
process.execPath
C'est l'absolu chemin de l'exécutable qui commencé le processus.
Exemple:
/ usr/local/bin/node
C’est un moyen relativement sûr et simple d’assurer la compatibilité entre le javascript côté serveur et côté client, qui fonctionne également avec browserify, RequireJS ou CommonJS inclus côté client:
(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 a un objet process
, aussi longtemps que vous n'avez aucun autre script créant process
, vous pouvez l'utiliser pour déterminer si le code s'exécute sur un noeud.
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: En ce qui concerne votre question mise à jour: "Comment un script peut-il indiquer s’il a été requis en tant que module commonjs?" Je ne le pense pas. Vous pouvez vérifier si exports
est un objet (if (typeof exports === "object")
), car la spécification nécessite qu'il soit fourni aux modules, mais tout ce qui vous dit, c'est que ... exports
est un objet. :-)
Réponse originale:
Je suis sûr qu'il existe un symbole spécifique à NodeJS ( non, vous devez utiliser EventEmitter
, peut-êtrerequire
pour obtenir le module des événements; voir ci-dessous) que vous pourriez vérifier, mais comme David l'a dit, idéalement, mieux vaut détecter la fonctionnalité (plutôt que l'environnement) si cela vous permet aucun sens de le faire.
Update: Peut-être quelque chose comme:
if (typeof require === "function"
&& typeof Buffer === "function"
&& typeof Buffer.byteLength === "function"
&& typeof Buffer.prototype !== "undefined"
&& typeof Buffer.prototype.write === "function") {
Mais cela vous indique simplement que vous êtes dans un environnement avec require
et quelque chose de très très similaire à celui de NodeJS Buffer
. :-)
const isNode =
typeof process !== 'undefined' &&
process.versions != null &&
process.versions.node != null;
Je pense que c'est assez simple.
if (process && process.title === 'node') {
// Your code here
}