Canonical Approach
You most likely need to use module: nodenext
in your tsconfig.json
.
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist"
},
"include": ["src"]
}
package.json
"type": "commonjs"
Now example files:
src/file.ts
export const example = async () => {
// find-up is a popular ES module on NPM
const module = await import("find-up");
return module.findUp
}
src/other.ts
import { example } from './file.js'
async function run() {
console.log('example', await example())
}
run()
Now run tsc
. The output in dist
will look like this:
dist/file.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.example = void 0;
const example = async () => {
const module = await import("find-up");
return module.findUp;
};
exports.example = example;
dist/other.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const file_js_1 = require("./file.js");
async function run() {
console.log('example', await (0, file_js_1.example)());
}
run();
Alternative Approach
If you can use Node.js >= 22.0.0 and if the ES module you are trying to load into CJS meets this criteria:
- The module is fully synchronous (contains no top-level
await
); and
- One of these conditions are met:
- The file has a
.mjs
extension.
- The file has a
.js
extension, and the closest package.json contains "type": "module"
- The file has a
.js
extension, the closest package.json
does not contain "type": "commonjs"
, and --experimental-detect-module
is enabled.
You can use --experimental-require-module
.
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "dist"
},
"include": ["src"]
}
package.json
"type": "commonjs"
src/file.ts
export const example = () => {
const module = require("find-up")
return module.findUp
}
src/other.ts
import { example } from './file.js'
function run() {
console.log('example', example())
}
run()
Now run tsc
to get the updated output in dist
.
Now run node --experimental-require-module dist/other.js
:
example [AsyncFunction: findUp]
(node:37823) ExperimentalWarning: Support for loading ES Module in require() is an experimental feature and might change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
eval
than a properly configured TS project? Your linked comment refers to this approach asquick and dirty
. – Jaala