web-dev-qa-db-fra.com

Comment vérifier si un script est en cours d'exécution sous node.js?

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?

135
theosp

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.

76
Ross

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à.

79
Ivo Wetzel

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.


Identifier Node.js uniquement

(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:

Identify Node (> = 3.0.0) ou io.js

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

Identify Node (> = 0.10.0) ou io.js

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

27
florianb

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.

25
TimE

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.

20
user3751385

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. 

  • Dans le navigateur, "ceci" est une référence à l'objet global, appelée "fenêtre".
  • Dans Node, 'this' fait référence au module.exports Object .
    • 'this' est pas une référence à l'objet global Node, appelé 'global'.
    • 'this' est not une référence à l'espace de déclaration de la variable du module.

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.

12
Patrick

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

Mais NE PAS !.

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.

La vie est courte!

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.

Et alors?

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;
}
10
Onur Yıldırım

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]';
9
Fabian Jakobs

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.

4
kybernetikos

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

4
Pete

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

4
Chris

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

4
Kevin Hakanson

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

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

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 (EventEmitter, peut-être non, vous devez utiliser require 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. :-)

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

Je pense que c'est assez simple.

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