J'ai un script que je demande à un script Node.js, que je souhaite garder indépendant du moteur JavaScript.
Par exemple, je veux le faire exports.x = y;
uniquement s'il fonctionne sous Node.js. Comment puis-je effectuer ce test?
En posant cette question, je ne savais pas que la fonctionnalité des modules Node.js était basée sur CommonJS .
Pour l'exemple spécifique que j'ai donné, une question plus précise aurait été:
Comment un script peut-il savoir s'il a été requis en tant que module CommonJS?
javascript
node.js
commonjs
theosp
la source
la source
Réponses:
En recherchant le support CommonJS , voici comment la bibliothèque Underscore.js le fait:
Modifier: à votre question mise à jour:
L'exemple ici conserve le modèle de module.
la source
Eh bien, il n'y a pas de moyen fiable de détecter l'exécution dans Node.js puisque chaque site Web peut facilement déclarer les mêmes variables, mais comme il n'y a pas d'
window
objet dans Node.js par défaut, vous pouvez aller dans l'autre sens et vérifier si vous exécutez dans un Navigateur.C'est ce que j'utilise pour les bibliothèques qui devraient fonctionner à la fois dans un navigateur et sous Node.js:
Cela peut encore exploser au cas où cela
window
est défini dans Node.js, mais il n'y a aucune bonne raison pour que quelqu'un fasse cela, car vous auriez explicitement besoin d'omettrevar
ou de définir la propriété sur l'global
objet.ÉDITER
Pour détecter si votre script a été requis en tant que module CommonJS, ce n'est encore une fois pas facile. 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 sur l'exports
objet. Maintenant, comment cela est mis en œuvre est laissé au système sous-jacent. Node.js enveloppe le contenu du module dans une fonction anonyme:Voir: https://github.com/ry/node/blob/master/src/node.js#L325
Mais n'essayez pas de détecter cela via des
arguments.callee.toString()
choses folles , utilisez simplement mon exemple de code ci-dessus qui vérifie le navigateur. Node.js est un environnement plus propre, il est donc peu probable qu'ilwindow
y soit déclaré.la source
window
dans la première ligne de votre module, vous ne devriez pas avoir de problèmes. Vous pouvez également exécuter une fonction anonyme et vérifiez la[[Class]]
de l'this
intérieur (fonctionne uniquement en mode non-stricte) Voir « Classe » sous: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
pourrait être plus sûr cartypeof window === 'undefined'
échoue sur la portée des travailleurs Web.Je suis actuellement tombé sur une mauvaise détection de Node qui n'est pas conscient de l'environnement Node dans Electron en raison d'une détection de fonction trompeuse. Les solutions suivantes identifient explicitement l'environnement de processus.
Identifier Node.js uniquement
Cela permettra de découvrir si vous exécutez dans un processus Node, car
process.release
contient les "métadonnées liées à la version actuelle de [Node-]".Après l' apparition de io.js, la valeur de
process.release.name
peut également devenirio.js
(voir le processus-doc ). Pour détecter correctement un environnement prêt pour les nœuds, je suppose que vous devez vérifier ce qui suit:Identifier le nœud (> = 3.0.0) ou io.js
Cette déclaration a été testée avec Node 5.5.0, Electron 0.36.9 (avec Node 5.1.1) et Chrome 48.0.2564.116.
Identifier le nœud (> = 0.10.0) ou io.js
Le commentaire de @ daluege m'a inspiré à 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.
Ps: Je poste cette réponse ici puisque la question m'amène ici, bien que l'OP recherchait une réponse à une question différente.
la source
process
etprocess.version
existe dans le bundle, j'ai donc ajouté une vérification supplémentaire pour savoirprocess.version
oùprocess.release.node
n'est pas défini du côté client mais a une version de nœud comme valeur côté serveurprocess.version
variable (dans react, webpack ou react-webpack). J'apprécierais tout indice où la variable de version est définie pour l'ajouter à la réponse. En fonction des contraintes de release.node au nœud> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
Le problème lorsque vous essayez de déterminer dans quel environnement votre code s'exécute 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 est en fait parfaitement adaptée pour le côté serveur, car lorsque la
require
fonction est appelée, elle réinitialise l'this
objet à un objet vide et redéfinitmodule
pour vous à nouveau, ce qui signifie que vous n'avez pas à vous soucier de toute falsification extérieure. Tant que votre code est chargé avecrequire
, vous êtes en sécurité.Cependant, cela s'effondre sur le navigateur, car tout le monde peut facilement définir
module
pour donner l'impression que c'est l'objet que vous recherchez. D'une part, cela peut être le comportement que vous souhaitez, mais cela détermine également les variables que l'utilisateur de la bibliothèque peut utiliser dans la portée globale. Peut-être que quelqu'un veut utiliser une variable avec le nommodule
qui s'y trouveexports
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?L'astuce cependant, c'est que si nous supposons que votre script est en cours de chargement dans la portée globale (ce qu'il sera s'il est chargé via une balise de script), une variable ne peut pas être réservée dans une fermeture externe, car le navigateur ne le permet pas . Souvenez-vous maintenant que dans node, l'
this
objet est un objet vide, pourtant, lamodule
variable est toujours disponible. C'est parce qu'il est déclaré dans une fermeture externe. Nous pouvons donc corriger la vérification du soulignement en ajoutant une vérification supplémentaire:this.module !== module
Avec cela, si quelqu'un déclare
module
dans la portée globale dans le navigateur, il sera placé dans l'this
objet, ce qui entraînera l'échec du test, car cethis.module
sera le même objet que le module. Sur le nœud,this.module
n'existe pas etmodule
existe dans une fermeture externe, donc le test réussira, car ils ne sont pas équivalents.Ainsi, le test final est:
typeof module !== 'undefined' && this.module !== module
Remarque: Bien que cela permette maintenant à la
module
variable d'être utilisée librement dans la portée globale, il est toujours possible de contourner cela sur le navigateur en créant une nouvelle fermeture et en déclarant à l'module
intérieur, puis en chargeant le script dans cette fermeture. À ce stade, l'utilisateur réplique entièrement l'environnement de nœud et, espérons-le, sait ce qu'il fait et essaie de faire 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.la source
Cannot read property 'module' of undefined
parce que cela n'est pas défini dans les tests moka par exempleLes éléments suivants fonctionnent dans le navigateur à moins d'être sabotés intentionnellement et explicitement:
Bam.
la source
process+''
place deprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
ferait échouer le deuxième cas. En Javascript et en Java, l'expression'' + x
produit la même chose quex.toString()
sauf quandx
est méchant, le premier produit"null"
ou"undefined"
lorsque le second lèverait une erreur.Voici une façon assez cool de le faire aussi:
Cela fonctionne parce que dans les navigateurs, la variable globale «this» a une auto-référence appelée «fenêtre». Cette auto-référence n'existe pas dans Node.
Pour briser la vérification du navigateur suggérée ci-dessus, vous devez faire quelque chose comme ce qui suit
avant d'exécuter la vérification.
la source
const isBrowser = this.window !== undefined
? Et en théorie, dans le nœud, je peux fairethis.window = this
pour tromper la solution.Encore une autre détection d'environnement :
(Ce qui signifie: la plupart des réponses ici sont correctes.)
Un peu paranoïaque non? Vous pouvez rendre cela plus détaillé en recherchant plus de globaux .
Mais NE PAS!.
Tout ce qui précède peut être truqué / simulé de toute façon.
Par exemple pour simuler l'
global
objet:Cela ne sera pas attaché à l'objet global d'origine du nœud mais il sera attaché à l'
window
objet dans un navigateur. Cela impliquera donc que vous êtes dans Node env dans un navigateur.La vie est courte!
Est-ce que nous nous soucions si notre environnement est truqué? Cela arriverait quand un développeur stupide déclarait une variable globale appelée
global
dans la portée globale. Ou un développeur maléfique 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 en compte. Donc, finalement, le code se cassera. 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 vérifiez simplementwindow
ouglobal
; et indiquez clairement que dans la documentation que votre code ne prend en charge que ces environnements. C'est tout!Si possible pour votre cas d'utilisation; au lieu de la détection d'environnement; faire une détection de fonction synchrone dans un bloc try / catch. (ceux-ci prendront quelques millisecondes pour s'exécuter).
par exemple
la source
La plupart des solutions proposées peuvent en fait être truquées. Une méthode robuste consiste à vérifier la
Class
propriété interne de l'objet global à l'aide duObject.prototype.toString
. La classe interne ne peut pas être falsifiée en JavaScript:la source
Object.prototype.toString
ce qui est vraiment une mauvaise pratique.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
c'est égal"[object global]"
.window.toString()
produit"[object Window]"
Qu'en est- il d' utiliser l'objet de processus et de contrôle execPath pour
node
?la source
window.process = {execPath: "/usr/local/bin/node"};
?Lié: pour vérifier si cela a été requis en tant que module vs exécuté directement dans le nœud, vous pouvez vérifier
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_modulela source
Voici ma variation sur ce qui précède:
Pour l'utiliser, vous modifiez la "Maison" sur l'avant-dernière ligne pour qu'elle soit ce que vous voulez que le nom du module soit dans le navigateur et publiez ce que vous voulez que la valeur du module soit (généralement un constructeur ou un objet littéral ).
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 probablement pas à moins que vous ne soyez dans un navigateur ou dans un environnement qui veut que vous croyiez que vous êtes dans un navigateur. Dans tous les autres cas, s'il y a une variable globale 'module' déclarée, il l'utilise sinon il utilise l'objet global.
la source
J'utilise
process
pour vérifier node.js comme çaou
Documenté ici
la source
process.title
peut être changéAu moment d'écrire ces lignes, cette réponse est plus une option "à venir", car elle exploite de très nouvelles fonctionnalités de JavaScript.
La
runtime
valeur sera soitnode
ounot node
.Comme mentionné, cela repose sur quelques nouvelles fonctionnalités JavaScript.
globalThis
est une fonctionnalité finalisée dans la spécification ECMAScript 2020. Le chaînage facultatif / la fusion nulle (la?
partie deglobalThis.process?.release?.name
) est pris en charge dans le moteur V8, qui est livré avec Chrome 80. À partir du 8/04/2020, ce code fonctionnera dans le navigateur mais ne fonctionnera pas dans Node puisque la branche Node 13 utilise V8 7.9.xxx. Je crois que Node 14 (dont la sortie est prévue le 21/04/2020) est censé utiliser V8 8.x +.Cette approche s'accompagne d'une bonne dose de restrictions actuelles. Toutefois; le rythme auquel les navigateurs / Node sont publiés, ce sera finalement un one-liner fiable.
la source
Node.js a un
process
objet, donc tant que vous n'avez aucun autre script qui crée,process
vous pouvez l'utiliser pour déterminer si le code s'exécute sur Node.la source
C'est un moyen assez sûr et simple d'assurer la compatibilité entre le javascript côté serveur et côté client, qui fonctionnera également avec browserify, RequireJS ou CommonJS inclus côté client:
la source
Edit : Concernant votre question mise à jour: "Comment un script peut-il dire s'il a été requis en tant que module commonjs?" Je ne pense pas que ce soit possible. Vous pouvez vérifier s'il
exports
s'agit d'un objet (if (typeof exports === "object")
), car la spécification exige qu'il soit fourni aux modules, mais tout ce qui vous dit est que ...exports
est un objet. :-)Réponse originale:
Je suis sûr qu'il y a un symbole spécifique à NodeJS (
non, vous devez utiliserEventEmitter
peut-être querequire
pour obtenir le module d'événements; voir ci-dessous ) que vous pourriez vérifier, mais comme David l'a dit, idéalement, vous feriez mieux de détecter la fonctionnalité (plutôt que l'environnement) si cela a du sens de le faire.Mise à jour : Peut-être quelque chose comme:
Mais cela vous indique simplement que vous êtes dans un environnement avec
require
et quelque chose de très, très similaire à celui de NodeJSBuffer
. :-)la source
window
variable dans une application NodeJS. :-)window
dans un module NodeJS, afin qu'il puisse inclure du code qui reposait sur le fait d'window
être l'objet global et ne voulait pas modifier ce code. Je ne le ferais pas, tu ne le ferais pas, mais je parie que quelqu'un l'a fait. :-) Ou ils ont juste utiliséwindow
pour signifier autre chose.typeof process !== "undefined" && process.title === "node"
la source
À partir de la source du package de débogage:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
la source
Prenez la source de node.js et modifiez-la pour définir une variable comme
runningOnNodeJS
. Vérifiez cette variable dans votre code.Si vous ne pouvez pas avoir votre propre version privée de node.js, ouvrez une demande de fonctionnalité dans le projet. Demandez-leur de définir une variable qui vous donne la version de node.js que vous utilisez. Ensuite, vérifiez cette variable.
la source
window
global, je suppose que je vais déposer une demande de fonctionnalité sur celui-ci.var
instruction, des personnes qui la fuient simplement dans l'espace de noms global, eh bien, ils ne comprennent pas le concept de modules autonomes alorsTrès ancien message, mais je viens de le résoudre en enveloppant les instructions require dans un try - catch
la source