17

Is it possible to check if JavaScript file is being run directly or if it was required as part of an es6 module import.

for example a main script is included.

// main.js
import './other';

if (mainTest){
  console.log('This should run');
}

which imports a dependency.

// other.js
if (mainTest){
  console.log('This should never run');
}

including <script src=main.js></script> should result in the console message from main.js but not other.js.

I found the answer to this question with regards to node, but I am interested specifically for es6 imports

Community
  • 1
  • 1
Peter Saxton
  • 4,128
  • 5
  • 31
  • 50
  • 1
    No, ES6 modules do not make this information available. – Bergi Jan 19 '16 at 16:17
  • The specification is a work in progress. So we don't know yet what the final code to retrieve this information looks like. – Walle Cyril Apr 05 '16 at 17:22
  • See also [Detect whether ES Module is run from command line in Node](https://stackoverflow.com/q/57838022/1048572) – Bergi Jul 04 '20 at 17:16

6 Answers6

11

An alternative for ES6 modules is now supported in Node. Using the new import.meta builtin. (Don't forget to set "type": "module" in package.json.)

Example

// main.js
import "./lib.js"
import { fileURLToPath } from "url";

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  console.log("I print to stdout!");
}
// lib.js
import { fileURLToPath } from "url";

if (process.argv[1] === fileURLToPath(import.meta.url)) {
  console.log("I don't run, because I'm an imported module.");
}

$ node main.js output:

I print to stdout!

Utility function

I like to just import { isMain } from "./lib/utils.js" and pass import.meta.url to isMain().

import { argv } from "process"
import { fileURLToPath } from "url"
/**
 * Check if a module is the main module launched with the node process.
 * Meaning the module is NOT imported by another module,
 * but was directly invoked by `node`, like this: `$ node main.js`
 *
 * @example
 * ```js
 * // main.js
 * import lib from "./lib.js"
 * import { isMain } from "./utils.js"
 *
 * if (isMain(import.meta.url)) {
 *   console.log("I print to stdout")
 * }
 *
 * // lib.js
 * import { isMain } from "./utils"
 *
 * if (isMain(import.meta.url)) {
 *   console.log("I don't run, because I'm an imported module")
 * }
 * ```
 *
 * @param {string} moduleUrl needs to be `import.meta.url`
 * @returns {boolean} true if the module is the main module
 */
export function isMain(moduleUrl) {
  const modulePath = fileURLToPath(moduleUrl)
  const [_binPath, mainScriptPath] = argv
  return modulePath === mainScriptPath
}
Junaga
  • 290
  • 2
  • 15
7

module.parent will help you:

if(module.parent) {
    console.log('required module')
} else {
    console.log('main')
}
just-boris
  • 8,839
  • 5
  • 47
  • 78
1

module.parent was deprecated in Node.js v14.6.0, however we can use require.main.

function main() {
    console.log("You're running the main file!");
}

if (require.main === module) {
    main();
}

A related answer can be found here.

Edwin Pratt
  • 745
  • 9
  • 19
0

The solution I see there is just to define the variable in the script you're importing. I.e. you define mainTest in main.js, and then use your existing if block.

nicael
  • 17,612
  • 12
  • 55
  • 87
0

If you are running in Node.js with type module, and don't name your files the same, and don't want to import a library, and want 1 line of code, this'll work:

if(process.argv[1].split('/')[process.argv[1].split('/').length - 1] === import.meta.url.split('/')[import.meta.url.split('/').length - 1]) {
  console.log("called from commandline")
} else {
  console.log("imported")
}
JesterXL
  • 308
  • 1
  • 10
0

The following simple code is available.

import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);

if (__filename === process.argv[1]) {
  console.log("main");
} else {
  console.log("not main");
}
nemo
  • 1