Phát hiện nếu được gọi thông qua yêu cầu hoặc trực tiếp bằng dòng lệnh


298

Làm cách nào để phát hiện xem tệp Node.JS của tôi được gọi bằng SH: node path-to-filehay JS : require('path-to-file')?

Đây là Node.JS tương đương với câu hỏi trước đây của tôi trong Perl: Làm cách nào tôi có thể chạy tập lệnh Perl của mình chỉ khi nó không được tải với yêu cầu?


Câu trả lời:


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

Xem tài liệu cho việc này tại đây: https://nodejs.org/docs/latest/api/modules.html#modules_accessing_the_main_module


3
Có cách nào để làm được việc này? Tôi có mã (mà tôi không có quyền kiểm soát) thực hiện điều này, nhưng tôi cần phải yêu cầu () nó và để nó hoạt động như thể nó được gọi trực tiếp. Về cơ bản, tôi cần đánh lừa thứ gì đó sử dụng bài kiểm tra đó để nghĩ rằng nó được gọi trực tiếp.
Kevin

2
@Kevin Tôi không biết về việc này với require(), nhưng bạn có thể làm điều đó bằng cách nhập tệp sau đó chạy evaltrên đó hoặc bằng cách chạyrequire('child_process').exec('node the_file.js')
MalcolmOcean

Khi sử dụng các mô-đun ES với Node.js, bạn có thể sử dụng es-maingói để kiểm tra xem mô-đun có được chạy trực tiếp không.
Tim Schaub

91

Có một cách khác, ngắn hơn một chút (không được nêu trong các tài liệu được đề cập).

var runningAsScript = !module.parent;

Tôi đã phác thảo thêm chi tiết về cách tất cả những thứ này hoạt động dưới mui xe trong bài đăng trên blog này .


+1, tôi thích điều này hơn, nhưng tôi sẽ do dự trước khi chuyển câu trả lời được chấp nhận. :)
Trường Bryan

8
Như tôi đã chỉ ra, cách chính thức được ghi lại là cách @nicolaskruchten đã vạch ra. Đây chỉ là một thay thế, không cần phải chuyển câu trả lời được chấp nhận. Cả hai đều làm việc.
Thorsten Lorenz

10
Tôi đã phải sử dụng điều này chứ không phải là cách làm tài liệu - cách làm tài liệu làm việc cho ví dụ. node script.jsnhưng không phải cat script.js | node. Cách này làm việc cho cả hai.
Tim Malone

9

Tôi đã có một chút bối rối bởi thuật ngữ được sử dụng trong (các) giải thích. Vì vậy, tôi đã phải làm một vài bài kiểm tra nhanh.

Tôi thấy rằng những điều này tạo ra kết quả tương tự:

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

Và đối với những người bối rối khác (và để trả lời câu hỏi trực tiếp):

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

5

Giống như trong Python, tôi luôn thấy mình cố gắng nhớ cách viết đoạn mã chết tiệt này. Vì vậy, tôi quyết định tạo ra một mô-đun đơn giản cho nó. Tôi phải mất một chút để phát triển vì việc truy cập thông tin mô-đun của người gọi không phải là khó khăn, nhưng thật vui khi thấy nó có thể được thực hiện như thế nào.

Vì vậy, ý tưởng là gọi một mô-đun và hỏi nó nếu mô-đun người gọi là mô-đun chính. Chúng ta phải tìm ra mô-đun của chức năng người gọi. Cách tiếp cận đầu tiên của tôi là một biến thể của câu trả lời được chấp nhận:

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

Nhưng điều đó không được đảm bảo để làm việc. module.parentchỉ vào mô-đun đã tải chúng tôi vào bộ nhớ, không phải là mô-đun gọi chúng tôi. Nếu đó là mô-đun người gọi đã tải mô-đun trợ giúp này vào bộ nhớ, thì tốt thôi. Nhưng nếu không, chúng tôi bất lực. Vì vậy, chúng ta cần phải thử một cái gì đó khác. Giải pháp của tôi là tạo ra một dấu vết ngăn xếp và lấy tên mô-đun của người gọi từ đó:

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;
};

Bây giờ chúng ta có thể làm:

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

Hoặc dễ đọc hơn:

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

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

Không thể nào quên :-)


2
Rất tuyệt. Tôi thích nó khi các đoạn mã phổ biến được viết tắt thành một tên duy nhất. Điều chỉnh nhỏ:return require.main /*this is undefined if we started node interactively*/ && require.main.filename === callerModuleName;
masterxilo

4

Hãy thử điều này nếu bạn đang sử dụng các mô-đun ES6:

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

2
tào lao, của tôi process.mainModuleundefined
datdinhquoc

1
GHOSHHHH, tôi cần kiểm tra điều này trong tệp .mjs của tôi
datdinhquoc
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.