Ich habe ein Skript, das ich von einem Node.js-Skript benötige, um die JavaScript-Engine unabhängig zu halten.
Zum Beispiel möchte ich exports.x = y;
nur tun , wenn es unter Node.js läuft. Wie kann ich diesen Test durchführen?
Beim Posten dieser Frage wusste ich nicht, dass die Node.js- Modulfunktion auf CommonJS basiert .
Für das spezifische Beispiel, das ich gegeben habe, wäre eine genauere Frage gewesen:
Wie kann ein Skript feststellen, ob es als CommonJS-Modul erforderlich war?
javascript
node.js
commonjs
theosp
quelle
quelle
Antworten:
Wenn Sie nach CommonJS-Unterstützung suchen , geht die Bibliothek Underscore.js folgendermaßen vor :
Bearbeiten: zu Ihrer aktualisierten Frage:
Beispiel hier behält das Modulmuster bei.
quelle
Nun, es gibt keine zuverlässige Möglichkeit, das Ausführen in Node.js zu erkennen, da jede Website problemlos dieselben Variablen deklarieren kann. Da
window
Node.js jedoch standardmäßig kein Objekt enthält, können Sie umgekehrt vorgehen und prüfen, ob Sie in a ausgeführt werden Browser.Dies ist, was ich für Bibliotheken verwende, die sowohl in einem Browser als auch unter Node.js funktionieren sollten:
Es kann immer noch explodieren, falls dies
window
in Node.js definiert ist, aber es gibt keinen guten Grund für jemanden, dies zu tun, da Sievar
die Eigenschaft für dasglobal
Objekt explizit weglassen oder festlegen müssten .BEARBEITEN
Um festzustellen, ob Ihr Skript als CommonJS-Modul benötigt wurde, ist dies wiederum nicht einfach. CommonJS gibt lediglich an, dass A: Die Module über einen Aufruf der Funktion aufgenommen werden
require
und B: Die Module exportieren Dinge über Eigenschaften desexports
Objekts. Wie das nun implementiert wird, bleibt dem zugrunde liegenden System überlassen. Node.js verpackt den Inhalt des Moduls in eine anonyme Funktion:Siehe: https://github.com/ry/node/blob/master/src/node.js#L325
Aber versuchen Sie nicht , das über verrückte
arguments.callee.toString()
Dinge zu erkennen , sondern verwenden Sie einfach meinen Beispielcode, der oben nach dem Browser sucht. Node.js ist eine viel sauberere Umgebung, daher ist es unwahrscheinlich, dasswindow
sie dort deklariert wird.quelle
window
in der ersten Zeile Ihres Moduls importieren, sollten Sie keine Probleme haben. Sie könnten auch eine anonyme Funktion und überprüfen Sie die laufen[[Class]]
von seinemthis
Inneren (funktioniert nur in nicht-Strict - Modus) Siehe „Klasse“ unter: bonsaiden.github.com/JavaScript-Garden/#typeoftypeof self === 'object'
Dies ist möglicherweise sicherer, da dertypeof window === 'undefined'
Umfang der Web-Worker fehlschlägt.Ich bin derzeit über eine falsche Erkennung von Knoten gestolpert, die aufgrund einer irreführenden Funktionserkennung die Knotenumgebung in Electron nicht kennt . Die folgenden Lösungen identifizieren die Prozessumgebung explizit.
Identifizieren Sie nur Node.js.
Dadurch wird festgestellt, ob Sie in einem Knotenprozess ausgeführt werden, da dieser
process.release
die "Metadaten zur aktuellen [Knoten-] Version" enthält.Nach dem Spawn von io.js
process.release.name
kann auch der Wert von werdenio.js
(siehe Prozessdokument ). Um eine knotenbereite Umgebung richtig zu erkennen, sollten Sie Folgendes überprüfen:Identifizieren Sie den Knoten (> = 3.0.0) oder io.js.
Diese Aussage wurde mit Node 5.5.0, Electron 0.36.9 (mit Node 5.1.1) und Chrome 48.0.2564.116 getestet.
Identifizieren Sie den Knoten (> = 0,10,0) oder io.js.
Der Kommentar von @ daluege hat mich dazu inspiriert, über einen allgemeineren Beweis nachzudenken. Dies sollte ab Node.js> = 0.10 funktionieren . Ich habe keine eindeutige Kennung für frühere Versionen gefunden.
Ps: Ich poste diese Antwort hier, da mich die Frage hierher geführt hat, obwohl das OP nach einer Antwort auf eine andere Frage gesucht hat.
quelle
process
undprocess.version
es im Bundle vorhanden ist. Daher habe ich eine zusätzliche Überprüfung hinzugefügt,process.version
woprocess.release.node
auf der Clientseite undefiniert ist, auf der Serverseite jedoch eine Knotenversion als Wertprocess.version
Variablen finden (in React, Webpack oder React-Webpack). Ich würde mich über jeden Hinweis freuen, in dem die Versionsvariable definiert ist, um sie der Antwort hinzuzufügen. Abhängig von release.node Einschränkungen für Knoten> = 3.xxfunction isNodejs() { return typeof "process" !== "undefined" && process && process.versions && process.versions.node; }
Das Problem beim Versuch herauszufinden, in welcher Umgebung Ihr Code ausgeführt wird, besteht darin, dass jedes Objekt geändert und deklariert werden kann, sodass es nahezu unmöglich ist, herauszufinden, welche Objekte in der Umgebung nativ sind und welche vom Programm geändert wurden.
Es gibt jedoch einige Tricks, mit denen wir herausfinden können, in welcher Umgebung Sie sich befinden.
Beginnen wir mit der allgemein akzeptierten Lösung, die in der Unterstrichbibliothek verwendet wird:
typeof module !== 'undefined' && module.exports
Diese Technik ist für die Serverseite eigentlich vollkommen in Ordnung, da beim
require
Aufrufen der Funktion dasthis
Objekt auf ein leeres Objekt zurückgesetzt undmodule
für Sie neu definiert wird, sodass Sie sich keine Gedanken über Manipulationen von außen machen müssen. Solange Ihr Code mit geladen istrequire
, sind Sie sicher.Dies fällt jedoch im Browser auseinander, da jeder leicht definieren kann
module
, dass es so aussieht, als wäre es das Objekt, nach dem Sie suchen. Dies kann einerseits das gewünschte Verhalten sein, bestimmt aber auch, welche Variablen der Bibliotheksbenutzer im globalen Bereich verwenden kann. Vielleicht hat jemand will eine Variable mit dem Namen verwendenmodule
, der hatexports
in der es für eine andere Verwendung. Es ist unwahrscheinlich, aber wer sollen wir beurteilen, welche Variablen jemand anderes verwenden kann, nur weil eine andere Umgebung diesen Variablennamen verwendet?Der Trick ist jedoch, dass, wenn wir davon ausgehen, dass Ihr Skript im globalen Bereich geladen wird (was auch der Fall ist, wenn es über ein Skript-Tag geladen wird), eine Variable nicht in einem äußeren Abschluss reserviert werden kann, da der Browser dies nicht zulässt . Denken Sie nun daran, dass das
this
Objekt im Knoten ein leeres Objekt ist und diemodule
Variable dennoch verfügbar ist. Das liegt daran, dass es in einem äußeren Verschluss deklariert ist. So können wir den Check des Unterstrichs korrigieren, indem wir einen zusätzlichen Check hinzufügen:this.module !== module
Wenn jemand
module
im Browser den globalen Bereich deklariert , wird er imthis
Objekt platziert, wodurch der Test fehlschlägt, da erthis.module
dasselbe Objekt wie das Modul ist. Auf dem Knoten istthis.module
nicht vorhanden undmodule
befindet sich innerhalb eines äußeren Verschlusses, sodass der Test erfolgreich ist, da sie nicht gleichwertig sind.Somit ist der letzte Test:
typeof module !== 'undefined' && this.module !== module
Hinweis: Auf diese Weise kann die
module
Variable jetzt im globalen Bereich frei verwendet werden. Sie können dies jedoch im Browser umgehen, indem Sie einen neuen Abschluss erstellen und diesen deklarierenmodule
und dann das Skript in diesen Abschluss laden. Zu diesem Zeitpunkt repliziert der Benutzer die Knotenumgebung vollständig und weiß hoffentlich, was er tut, und versucht, einen erforderlichen Knotenstil auszuführen. Wenn der Code in einem Skript-Tag aufgerufen wird, ist er weiterhin vor neuen äußeren Verschlüssen geschützt.quelle
Cannot read property 'module' of undefined
weil dies zum Beispiel in Mokka-Tests undefiniert istFolgendes funktioniert im Browser, sofern nicht absichtlich explizit sabotiert:
Bam.
quelle
process+''
anstelle von verwendenprocess.toString()
?Object.prototype.toString.call(process)
var process = null;
würde dazu führen, dass der zweite Fall fehlschlägt. Sowohl in Javascript als auch in Java'' + x
erzeugt der Ausdruck dasselbe,x.toString()
außer wenn erx
böse ist, der erstere erzeugt"null"
oder"undefined"
wo der letztere einen Fehler auslösen würde.Hier ist eine ziemlich coole Möglichkeit, dies ebenfalls zu tun:
Dies funktioniert, weil in Browsern die globale Variable 'this' eine Selbstreferenz namens 'window' hat. Diese Selbstreferenz ist in Node nicht vorhanden.
Um die oben vorgeschlagene Browserüberprüfung zu unterbrechen, müssten Sie Folgendes tun
vor dem Ausführen der Prüfung.
quelle
const isBrowser = this.window !== undefined
? Und theoretisch kann ich im Knotenthis.window = this
die Lösung täuschen.Noch eine Umgebungserkennung :
(Das heißt: Die meisten Antworten hier sind in Ordnung.)
Ein bisschen paranoid, oder? Sie können dies ausführlicher gestalten, indem Sie nach mehr Globalen suchen .
Aber NICHT!.
All dies kann sowieso gefälscht / simuliert werden.
Zum Beispiel, um das
global
Objekt zu fälschen :Dies wird nicht an das ursprüngliche globale Objekt des Knotens angehängt, sondern an das
window
Objekt in einem Browser. Es bedeutet also, dass Sie sich in Node env in einem Browser befinden.Das Leben ist kurz!
Interessiert es uns, wenn unsere Umwelt gefälscht ist? Es würde passieren, wenn ein dummer Entwickler eine globale Variable deklariert, die
global
im globalen Bereich aufgerufen wird . Oder ein böser Entwickler fügt irgendwie Code in unsere Umgebung ein.Wir können verhindern, dass unser Code ausgeführt wird, wenn wir dies abfangen, aber viele andere Abhängigkeiten unserer App können davon betroffen sein. Also wird der Code irgendwann kaputt gehen. Wenn Ihr Code gut genug ist, sollten Sie sich nicht um jeden dummen Fehler kümmern, den andere hätten machen können.
Na und?
Wenn Sie auf zwei Umgebungen abzielen: Browser und Knoten;
"use strict"
;; und entweder einfach nachwindow
oder suchenglobal
; und geben Sie in den Dokumenten deutlich an, dass Ihr Code nur diese Umgebungen unterstützt. Das ist es!Wenn möglich für Ihren Anwendungsfall; anstelle der Umgebungserkennung; Führen Sie eine synchrone Feature-Erkennung innerhalb eines Try / Catch-Blocks durch. (Die Ausführung dauert einige Millisekunden).
z.B
quelle
Die meisten der vorgeschlagenen Lösungen können tatsächlich gefälscht werden. Eine robuste Methode besteht darin, die interne
Class
Eigenschaft des globalen Objekts mithilfe von zu überprüfenObject.prototype.toString
. Die interne Klasse kann in JavaScript nicht gefälscht werden:quelle
Object.prototype.toString
was wirklich eine schlechte Praxis ist.var global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};
({}.toString.call(window))
ist gleich"[object global]"
.window.toString()
produziert"[object Window]"
Was ist das Prozessobjekt und Überprüfung mit execPath für
node
?quelle
window.process = {execPath: "/usr/local/bin/node"};
?Verwandte: Um zu überprüfen, ob es als Modul erforderlich war oder direkt im Knoten ausgeführt wird, können Sie überprüfen
require.main !== module
. http://nodejs.org/docs/latest/api/modules.html#accessing_the_main_modulequelle
Hier ist meine Variation von dem, was oben steht:
Um es zu verwenden, ändern Sie das "Haus" in der vorletzten Zeile so, dass der Name des Moduls im Browser angezeigt wird, und veröffentlichen den gewünschten Wert des Moduls (normalerweise ein Konstruktor oder ein Objektliteral) ).
In Browsern ist das globale Objekt window und hat einen Verweis auf sich selbst (es gibt ein window.window, das == window ist). Es scheint mir, dass dies unwahrscheinlich ist, wenn Sie sich nicht in einem Browser oder in einer Umgebung befinden, in der Sie glauben sollen, dass Sie sich in einem Browser befinden. In allen anderen Fällen, wenn eine globale 'Modul'-Variable deklariert ist, wird diese verwendet, andernfalls wird das globale Objekt verwendet.
quelle
Ich verwende
process
, um nach node.js zu suchenoder
dokumentierte hier
quelle
process.title
kann geändert werdenZum jetzigen Zeitpunkt handelt es sich bei dieser Antwort eher um eine "Coming Soon" -Option, da sie sehr neue Funktionen von JavaScript nutzt.
Der
runtime
Wert ist entwedernode
odernot node
.Wie bereits erwähnt, basiert dies auf einigen neuen JavaScript-Funktionen.
globalThis
ist eine endgültige Funktion in der ECMAScript 2020-Spezifikation. In der V8-Engine, die im Lieferumfang von Chrome 80 enthalten ist, wird optionales Verketten / Null-Zusammenführen (der?
Teil vonglobalThis.process?.release?.name
) unterstützt. Ab dem 08.04.2020 funktioniert dieser Code im Browser, jedoch nicht in Node, da der Node 13-Zweig verwendet V8 7.9.xxx. Ich glaube, dass Node 14 (voraussichtlich am 21.04.2020 veröffentlicht) V8 8.x + verwenden soll.Dieser Ansatz bringt eine gesunde Dosis aktueller Einschränkungen mit sich. Jedoch; Das Tempo, mit dem Browser / Knoten veröffentlicht werden, wird letztendlich ein zuverlässiger Einzeiler sein.
quelle
Node.js hat ein
process
Objekt. Solange Sie kein anderes Skript haben, das erstellt wird,process
können Sie damit bestimmen, ob Code auf Node ausgeführt wird.quelle
Dies ist eine ziemlich sichere und unkomplizierte Methode, um die Kompatibilität zwischen serverseitigem und clientseitigem Javascript sicherzustellen, das auch mit browserify, RequireJS oder CommonJS einschließlich clientseitig funktioniert:
quelle
Bearbeiten : Zu Ihrer aktualisierten Frage: "Wie kann ein Skript feststellen, ob es als CommonJS-Modul erforderlich war?" Ich glaube nicht, dass es geht. Sie können überprüfen, ob
exports
es sich um ein Objekt (if (typeof exports === "object")
) handelt, da die Spezifikation die Bereitstellung für Module erfordert. Sie müssen jedoch nur angeben, dass ...exports
ein Objekt ist. :-)Ursprüngliche Antwort:
Ich bin mir sicher, dass es ein NodeJS-spezifisches Symbol gibt (
nein, Sie müssen es verwendenEventEmitter
vielleichtrequire
, um das Ereignismodul abzurufen; siehe unten ), nach dem Sie suchen könnten, aber wie David sagte, ist es im Idealfall besser, die Funktion zu erkennen (eher als Umwelt), wenn es Sinn macht, dies zu tun.Update : Vielleicht so etwas wie:
Aber das sagt dir nur, dass du in einer Umgebung mit
require
und etwas sehr, sehr ähnlichem wie NodeJS bistBuffer
. :-)quelle
window
aufheben , indem ich eine Variable in einer NodeJS-Anwendung definiere. :-)window
in einem NodeJS Modul, so dass sie Code enthalten könnten , die Verlasswindow
ist das globale Objekt und nicht , dass Code ändern möchten. Ich würde es nicht tun, du würdest es nicht tun , aber ich wette, jemand hat es getan . :-) Oder sie haben einfachwindow
etwas ganz anderes gemeint.typeof process !== "undefined" && process.title === "node"
quelle
Aus der Quelle des Debug-Pakets:
https://github.com/visionmedia/debug/blob/master/src/index.js#L6
quelle
Nehmen Sie die Quelle von node.js und ändern Sie sie, um eine Variable wie zu definieren
runningOnNodeJS
. Suchen Sie in Ihrem Code nach dieser Variablen.Wenn Sie keine eigene private Version von node.js haben können, öffnen Sie eine Funktionsanforderung im Projekt. Bitten Sie sie, eine Variable zu definieren, die Ihnen die Version von node.js gibt, in der Sie ausgeführt werden. Überprüfen Sie dann, ob diese Variable vorhanden ist.
quelle
window
globales erstellen. Ich schätze, ich werde eine Feature-Anfrage für dieses Skript einreichen.var
Anweisung, Leute, die sie nur in den globalen Namespace lecken, und sie bekommen dann nicht das Konzept von in sich geschlossenen ModulenSehr alter Beitrag, aber ich habe ihn gerade gelöst, indem ich die erforderlichen Anweisungen in einen Try-Catch eingewickelt habe
quelle