I am writing a JS function that could be used in both CommonJS & ESM Module system.
But it would do something different depending on which it ran in.
Is there any way to test in runtime code which system we are in?
My approach uses a separate spawned process to detect the current module system a file is running under.
The script run as a child process:
checkType.js
import('node:process').then(({ stdout }) => {
try {
require.main
} catch {
stdout.write('module')
return 'module'
}
try {
import.meta
} catch {
stdout.write('commonjs')
return 'commonjs'
}
})
The parent process used to determine the runtime module context:
moduleType.js
import { resolve } from 'node:path'
import { spawnSync } from 'node:child_process'
export const moduleType = () => {
const { stdout, stderr } = spawnSync('node', [resolve(import.meta.dirname, 'checkType.js')])
let type = 'unknown'
// Only one of these will be non-falsy strings
const err = stderr.toString()
const out = stdout.toString()
/**
* Based on error messaging from v8
* @see https://github.com/nodejs/node/blob/bc13f23f7e25d750df9b0a7bfe891a3d69f995f3/deps/v8/src/common/message-template.h#L124
*/
if (/outside a module/i.test(err)) {
type = 'commonjs'
}
if (out) {
type = out
}
return type
}
moduleType.js gets converted to both ESM and CJS modules during a build, and this might be useful in other toolchains like TypeScript.
some-file.ts
import { moduleType } from 'node-module-type'
console.log(`ts file running in module mode ${moduleType()}`
Now when you execute this file with something like tsx, the module type is determined by whatever the "type" is in package.json, or the file extension (.cts or .mts).
Whether this is ultimately useful depends on if any use cases exist beyond publishing dual packages. FWIW, I made this functionality available on npm under node-module-type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With