Node.js utility for transforming a JavaScript or TypeScript file from an ES module to CommonJS, or vice versa.
- ES module ➡️ CommonJS
- CommonJS ➡️ ES module
By default @knighted/module
transforms the one-to-one differences between ES modules and CommonJS, but it also accepts options that allow:
- Converting
import
/export
torequire
/exports
- Extensions to be updated in relative specifiers
- Write transformed source code to a filename
- Node >= 20.11.0
Given an ES module
file.js
import { argv } from 'node:process'
import { pathToFileURL } from 'node:url'
import { realpath } from 'node:fs/promises'
const detectCalledFromCli = async path => {
const realPath = await realpath(path)
if (import.meta.url === pathToFileURL(realPath).href) {
console.log('invoked directly by node')
}
}
detectCalledFromCli(argv[1])
You can transform it to the equivalent CommonJS module
import { transform } from '@knighted/module'
await transform('./file.js', {
type: 'commonjs'
moduleLoading: true,
out: './file.cjs'
})
Which produces
file.cjs
const { argv } = require('node:process')
const { pathToFileURL } = require('node:url')
const { realpath } = require('node:fs/promises')
const detectCalledFromCli = async path => {
const realPath = await realpath(path)
if (require('node:url').pathToFileURL(__filename).toString() === pathToFileURL(realPath).href) {
console.log('invoked directly by node')
}
}
detectCalledFromCli(argv[1])
When executed from the CLI
use@computer: $ node file.cjs
invoked directly by node
type ModuleOptions = {
/* What module system to convert to. */
type?: 'module' | 'commonjs'
/* Whether import/export and require/exports should be transformed. */
modules?: boolean
/* Whether to change specifier extensions to the assigned value. If omitted they are left alone. */
specifier?: '.js' | '.mjs' | '.cjs' | '.ts' | '.mts' | '.cts'
/* What filepath to write the transformed source to. */
out?: string
}
- Support option
modules
. - Remove
@knighted/specifier
and avoid double parsing.