An ESM module can be used in two ways:
If we want a module to be used in both ways, we need a way to check if the current module is the main module because only then do we execute the script functionality. In this blog post, we learn how to perform that check.
With CommonJS, we can use the following pattern to detect if the current module was the entry point (source: Node.js documentation):
if (require.main === module) {
// Main CommonJS module
}
As of now, ESM modules have no simple built-in way to check if a module is main. Instead, we have to use the following workaround (based on a tweet by Rich Harris):
import * as url from 'node:url';
if (import.meta.url.startsWith('file:')) { // (A)
const modulePath = url.fileURLToPath(import.meta.url);
if (process.argv[1] === modulePath) { // (B)
// Main ESM module
}
}
Explanations:
import.meta.url
contains the URL of the currently executed ESM module.
If we are sure our code always runs locally (which may become less common in the future), we can omit the check in line A. If we do and the code does not run locally, at least we get an exception (and not a silent failure) – thanks to url.fileURLToPath()
(see next item).
We use url.fileURLToPath()
to convert the URL to a local path. This function throws an exception if the protocol isn’t file:
.
process.argv[1]
contains the path of the initial module. The comparison in line B works because this value is always an absolute path – Node.js sets it up as follows (source code):
process.argv[1] = path.resolve(process.argv[1]);