Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

detect whether ES Module is run from command line in Node

When using CommonJS modules in Node, you can detect whether a script is being run from the command line using require.main === module.

What is an equivalent way to detect whether a script is being run from the command line when using ES Modules in Node (with the --experimental-modules flag)?

like image 614
dwhieb Avatar asked Sep 07 '19 23:09

dwhieb


3 Answers

Use

if (import.meta.url === `file://${process.argv[1]}`) {
  // module was not imported but called directly
}

See the MDN docs on import.meta for details.

Update Sep 27, 2021

Perhaps more robust, but involving an extra import (via Rich Harris)

import {pathToFileURL} from 'url'

if (import.meta.url === pathToFileURL(process.argv[1]).href) {
  // module was not imported but called directly
}
like image 184
Casimir Avatar answered Nov 07 '22 13:11

Casimir


There is none - yet (it's still experimental!). Although the prevailing opinion is that such a check is a bad practice anyway and you should just provide separate scripts for the library and the executable, there is an idea to provide a boolean import.meta.main property for this purpose.

like image 7
Bergi Avatar answered Nov 07 '22 13:11

Bergi


The other answers get close, but will miss the mark for a pretty typical usecase - cli scripts exposed by the bin property in package.json files.

These scripts will be symlinked in the node_modules/.bin folder. These can be invoked through npx or as scripts defined in the scripts-object in package.json. process.argv[1] will in that case be the symlink and not the actual file referenced by import.meta.url

Furthermore, we need to convert the file path to an actual file://-url otherwise it will not work correctly on different platforms.

import { realpathSync } from "fs";
import { pathToFileURL } from "url";

function wasCalledAsScript() {
    // We use realpathSync to resolve symlinks, as cli scripts will often
    // be executed from symlinks in the `node_modules/.bin`-folder
    const realPath = realpathSync(process.argv[1]);

    // Convert the file-path to a file-url before comparing it
    const realPathAsUrl = pathToFileURL(realPath).href;
  
    return import.meta.url === realPathAsUrl;
}

if (wasCalledAsScript()) {
  // module was executed and imported by another file.
}

I would have posted this as a comment on the accepted answer, but apparently I'm not allowed to comment with a fresh account.

like image 3
gustavnikolaj Avatar answered Nov 07 '22 13:11

gustavnikolaj