Я пытаюсь загрузить один модуль ESM в свой проект TypeScript CJS. Все примеры, которые я нахожу, предназначены для JavaScript.
// example.ts
export const example = async () => {
const module = await import("esm-module");
return module.func
}
Моя проблема в том, что TSC переносит функцию import в требование, которое все ломает.
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.example = void 0;
const example = async () => {
const module = await Promise.resolve().then(() => require("esm-module")); // Not desired
return module.func;
};
exports.example = example
Я наткнулся на этот комментарий - Не уверен, что сейчас есть лучший способ. По крайней мере, eval
используется с постоянной строкой, поэтому я не вижу проблем с линтингом.
// example.ts
type EsmModule = typeof import("esm-module");
export const example = async () => {
const module = await (eval('import("esm-module")') as Promise<EsmModule>);
return module.func
}
Большинство других решений усложняют основную предпосылку и либо пытаются испортить tsconfig.json
или package.json
, либо неправильно учитывают транспиляцию TypeScript.
Скорее всего, вам придется использовать module: nodenext
в своем tsconfig.json
.
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist"
},
"include": ["src"]
}
пакет.json
"type": "commonjs"
Теперь примеры файлов:
источник/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.info('example', await example())
}
run()
Теперь бегите tsc
. Вывод в dist
будет выглядеть так:
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.info('example', await (0, file_js_1.example)());
}
run();
Если вы можете использовать Node.js >= 22.0.0 и если модуль ES, который вы пытаетесь загрузить в CJS, соответствует этому критерию:
- Модуль полностью синхронный (не содержит верхнего уровня
await
); и- Одно из этих условий соблюдено:
- Файл имеет расширение
.mjs
.- Файл имеет расширение
.js
, а ближайший package.json содержит"type": "module"
.- Файл имеет расширение
.js
, ближайшийpackage.json
не содержит"type": "commonjs"
и--experimental-detect-module
включен.
Вы можете использовать --experimental-require-module.
tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"module": "CommonJS",
"moduleResolution": "Node",
"outDir": "dist"
},
"include": ["src"]
}
пакет.json
"type": "commonjs"
источник/file.ts
export const example = () => {
const module = require("find-up")
return module.findUp
}
src/other.ts
import { example } from './file.js'
function run() {
console.info('example', example())
}
run()
Теперь запустите tsc
, чтобы получить обновленный результат в dist
.
Теперь запустите 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)