406 Stimmen

Erkennen, ob der Aufruf über require oder direkt über die Befehlszeile erfolgt

Wie kann ich feststellen, ob meine Node.JS-Datei mit SH aufgerufen wurde: node path-to-file oder JS: require('path-to-file') ?

Dies ist das Node.JS-Äquivalent zu meiner vorherigen Frage in Perl: Wie kann ich mein Perl-Skript nur ausführen, wenn es nicht mit require geladen wurde?

6voto

Kebot Punkte 257

Versuchen Sie dies, wenn Sie ES6-Module verwenden:

if (process.mainModule.filename === __filename) {
  console.log('running as main module')
}

6voto

Gabriel Punkte 3254

Wie kann ich feststellen, ob meine node.js-Datei direkt von der Konsole (Windows- und Unix-Systeme) aufgerufen oder mit Hilfe des ESM-Modulimports geladen wurde ( import {foo} from 'bar.js' )

Diese Funktionalität ist nicht offengelegt. Im Moment sollten Sie Ihre Cli- und Bibliothekslogik in getrennte Dateien aufteilen.

Antwort von node.js core contributor devsnek in Beantwortung von nodejs/hilfe/probleme/2420

Das ist meiner Meinung nach die richtige Antwort.

3voto

Jack G Punkte 3797

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.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X