27

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,466
  • 5
  • 33
  • 51
  • 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

7 Answers7

17

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
  • 292
  • 4
  • 19
8

module.parent will help you:

if(module.parent) {
    console.log('required module')
} else {
    console.log('main')
}
just-boris
  • 9,468
  • 5
  • 48
  • 84
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.

Ed The ''Pro''
  • 875
  • 10
  • 22
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
  • 18,550
  • 13
  • 57
  • 90
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
  • 2
  • 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
  • 11
-1

Here is a function which works for both CommonJS and ES6. Read the code comments for example usage. This is written in TypeScript but can be easily converted to any flavor of plain JS.

// const { fileURLToPath } = require('url');
import { fileURLToPath } from "url";

/** 
 * Determines whether a module is the entry point for the running node process.
 * This works for both CommonJS and ES6 environments.
 * 
 * ### CommonJS
 * ```js
 * if (moduleIsEntry(module)) {
 *     console.log('WOO HOO!!!');
 * }
 * ``` 
 * 
 * ### ES6
 * ```js
 * if (moduleIsEntry(import.meta.url)) {
 *     console.log('WOO HOO!!!');
 * }
 * ```
 */
const moduleIsEntry = (moduleOrImportMetaUrl: NodeModule | string) => {
    if (typeof moduleOrImportMetaUrl === 'string') {
        return process.argv[1] === fileURLToPath(moduleOrImportMetaUrl);
    }

    if (typeof require !== 'undefined' && 'exports' in moduleOrImportMetaUrl) {
        return require.main === moduleOrImportMetaUrl;
    }

    return false;
}
Ryan Wheale
  • 26,022
  • 8
  • 76
  • 96