'`if __name__ == '__main__'` equivalent in javascript es6 modules

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



Solution 1:[1]

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
}

Solution 2:[2]

module.parent will help you:

if(module.parent) {
    console.log('required module')
} else {
    console.log('main')
}

Solution 3:[3]

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.

Solution 4:[4]

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.

Solution 5:[5]

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")
}

Solution 6:[6]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 just-boris
Solution 3 Edwin Pratt
Solution 4 nicael
Solution 5 JesterXL
Solution 6 nemo