Mendeteksi jika dipanggil membutuhkan atau langsung oleh baris perintah


298

Bagaimana saya bisa mendeteksi apakah file Node.js saya dipanggil menggunakan SH: node path-to-fileatau JS: require('path-to-file')?

Ini adalah Node.JS yang setara dengan pertanyaan saya sebelumnya di Perl: Bagaimana saya bisa menjalankan skrip Perl saya hanya jika tidak dimuat dengan memerlukan?


Jawaban:


471
if (require.main === module) {
    console.log('called directly');
} else {
    console.log('required as a module');
}

Lihat dokumentasi untuk ini di sini: https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module


3
Apakah ada cara untuk mengatasi ini? Saya memiliki kode (yang saya tidak punya kendali atas) yang melakukan ini, tetapi saya perlu meminta () dan membuatnya bertindak seolah-olah itu dipanggil langsung. Pada dasarnya, saya perlu membodohi sesuatu yang menggunakan tes itu untuk berpikir itu disebut langsung.
Kevin

2
@Kevin Saya tidak tahu tentang melakukan ini dengan require(), tetapi Anda mungkin bisa melakukannya dengan mengimpor file kemudian berjalan evaldi atasnya, atau dengan menjalankanrequire('child_process').exec('node the_file.js')
MalcolmOcean

Saat menggunakan modul ES dengan Node.js, Anda dapat menggunakan es-mainpaket untuk memeriksa apakah modul dijalankan secara langsung.
Tim Schaub

91

Ada cara lain, sedikit lebih pendek (tidak diuraikan dalam dokumen yang disebutkan).

var runningAsScript = !module.parent;

Saya menjabarkan lebih rinci tentang bagaimana semua ini bekerja di bawah kap di posting blog ini .


+1, saya lebih suka ini, tetapi saya akan ragu sebelum mengalihkan jawaban yang diterima. :)
Lapangan Bryan

8
Seperti yang saya sebutkan, cara resmi yang didokumentasikan adalah yang diuraikan @nicolaskruchten. Ini hanya sebuah alternatif, tidak perlu mengganti jawaban yang diterima. Keduanya bekerja.
Thorsten Lorenz

10
Saya harus menggunakan ini daripada cara yang didokumentasikan - cara yang didokumentasikan berfungsi misalnya. node script.jstapi tidak cat script.js | node. Cara ini bekerja untuk keduanya.
Tim Malone

9

Saya sedikit bingung dengan terminologi yang digunakan dalam penjelasan. Jadi saya harus melakukan beberapa tes cepat.

Saya menemukan bahwa ini menghasilkan hasil yang sama:

var isCLI = !module.parent;
var isCLI = require.main === module;

Dan untuk orang-orang bingung lainnya (dan untuk menjawab pertanyaan secara langsung):

var isCLI = require.main === module;
var wasRequired = !isCLI;

5

Sama seperti di Python, saya selalu menemukan diri saya mencoba mengingat bagaimana menulis potongan kode sialan ini. Jadi saya memutuskan untuk membuat modul sederhana untuk itu. Butuh sedikit waktu untuk saya kembangkan karena mengakses informasi modul pemanggil tidak mudah, tetapi menyenangkan melihat bagaimana hal itu bisa dilakukan.

Jadi idenya adalah memanggil modul dan bertanya apakah modul pemanggil adalah yang utama. Kita harus mencari tahu modul fungsi pemanggil. Pendekatan pertama saya adalah variasi dari jawaban yang diterima:

module.exports = function () {
    return require.main === module.parent;
};

Tapi itu tidak dijamin berhasil. module.parentmenunjuk ke modul yang memuat kita ke dalam memori, bukan yang memanggil kita. Jika itu adalah modul pemanggil yang memuat modul pembantu ini ke dalam memori, itu tidak masalah. Tetapi jika tidak, kita tidak berdaya. Jadi kita perlu mencoba sesuatu yang lain. Solusi saya adalah menghasilkan jejak stack dan mendapatkan nama modul pemanggil dari sana:

module.exports = function () {
    // generate a stack trace
    const stack = (new Error()).stack;
    // the third line refers to our caller
    const stackLine = stack.split("\n")[2];
    // extract the module name from that line
    const callerModuleName = /\((.*):\d+:\d+\)$/.exec(stackLine)[1];

    return require.main.filename === callerModuleName;
};

Sekarang kita bisa melakukan:

if (require("./is-main-module")()) {  // notice the `()` at the end
    // do something
} else {
    // do something else
}

Atau lebih mudah dibaca:

const isMainModule = require("./is-main-module");

if (isMainModule()) {
    // do something
} else {
    // do something else
}

Mustahil untuk dilupakan :-)


2
Sangat keren. Saya suka ketika potongan kode umum disingkat menjadi satu nama. Penyesuaian kecil:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo

4

Coba ini jika Anda menggunakan modul ES6:

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

2
omong kosong, saya process.mainModuleyaituundefined
datdinhquoc

1
GHOSHHHH, saya perlu memeriksa ini di file .mjs saya
datdinhquoc
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.