Lassen Sie uns zunächst das Problem genauer definieren. Ich gehe davon aus, dass Sie eigentlich nur wissen wollen, ob Ihr Skript besitzt process.argv
(d.h. ob Ihr Skript für die Verarbeitung von process.argv
). Mit dieser Annahme im Hinterkopf sind der nachstehende Code und die Tests korrekt.
module.parent
funktioniert hervorragend, ist aber aus guten Gründen veraltet (ein Modul kann mehrere Eltern haben, in diesem Fall module.parent
nur für das erste Elternteil steht), so dass die folgende zukunftssichere Bedingung für alle Fälle gilt:
if (
typeof process === 'object' && process && process.argv
&& (
(
typeof module === 'object' && module
&& (
!module.parent
|| require.main === module
|| (process.mainModule && process.mainModule.filename === __filename)
|| (__filename === "[stdin]" && __dirname === ".")
)
)
|| (
typeof document === "object"
&& (function() {
var scripts = document.getElementsByTagName("script");
try { // in case we are in a special environment without path
var normalize = require("path").normalize;
for (var i=0,len=scripts.length|0; i < len; i=i+1|0)
if (normalize(scripts[i].src.replace(/^file:/i,"")) === __filename)
return true;
} catch(e) {}
})()
)
)
) {
// this module is top-level and invoked directly by the CLI
console.log("Invoked from CLI");
} else {
console.log("Not invoked from CLI");
}
Es funktioniert in allen Skripten in allen folgenden Fällen korrekt und gibt keine Fehler aus † :
- Die Anforderung des Skripts (z.B.
require('./main.js')
)
- Direktes Aufrufen des Skripts (z.B.
nodejs cli.js
)
- Vorladen eines anderen Skripts (z.B.
nodejs -r main.js cli.js
)
- Piping in Knoten-CLI (e.x.
cat cli.js | nodejs
)
- Rohrleitungen mit Vorspannung (z.B.
cat cli.js | nodejs -r main.js
)
- Bei Arbeitnehmern (z. B.
new Worker('./worker.js')
)
- En
eval
Arbeitnehmer (z.B. new Worker('if (<test for CLI>) ...', {eval: true})
)
- Innerhalb von ES6-Modulen (e.x.
nodejs --experimental-modules cli-es6.js
)
- Module mit Vorspannung (z.B.
nodejs --experimental-modules -r main-es6.js cli-es6.js
)
- Gepipte ES6-Module (e.x.
cat cli-es6.js | nodejs --experimental-modules
)
- Pipe+Preload-Modul (z.B..
cat cli-es6.js | nodejs --experimental-modules -r main-es6.js
)
- Im Browser (in diesem Fall ist CLI falsch, weil es keine
process.argv
)
- In gemischten Browser+Server-Umgebungen (z.B. ElectronJS, in dem Fall werden sowohl Inline-Skripte als auch alle Module, die über
<script>
Tags werden als CLI betrachtet)
Der einzige Fall, in dem es nicht funktioniert, ist, wenn Sie das Top-Level-Skript vorladen (z.B. nodejs -r cli.js cli.js
). Dieses Problem kann nicht durch Rohrleitungen gelöst werden (z.B. cat cli.js | nodejs -r cli.js
), da das Skript dadurch zweimal ausgeführt wird (einmal als erforderliches Modul und einmal als oberste Ebene). Ich glaube nicht, dass es eine mögliche Lösung für dieses Problem gibt, da es keine Möglichkeit gibt, zu wissen, was das Hauptskript innerhalb eines vorgeladenen Skripts sein wird.
† Theoretisch könnten Fehler innerhalb eines Getters für ein Objekt ausgelöst werden (z. B. wenn jemand verrückt genug wäre, um Object.defineProperty(globalThis, "process", { get(){throw 0} });
), jedoch wird dies unter Standardbedingungen für die im Codefragment verwendeten Eigenschaften in keiner Umgebung passieren.