Я пытаюсь загрузить один модуль 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.
Этот проект является устаревшим и имеет moduleResolution
как Node10
, но не может использовать Node 22 до тех пор, пока не перейдет в статус LTS в октябре. Я уже пробовал комбинацию настроек ts-config, но все равно сталкиваюсь с ошибкой ESM глубже внутри самого пакета ESM. Это единственное решение, которое работает в нашей текущей настройке. Однако в идеале да, я хотел бы перенести проект на ESNext и, в конечном итоге, на ESM, как только экосистема станет немного более стабильной.
Вам следует обновить свой вопрос, указав, какую версию модуля и/или узла вы должны использовать. Если вы можете использовать узел 20, который является LTS, вы сможете обновить разрешение модуля, чтобы избежать eval. Конечно, это зависит от того, какую ошибку вы увидели при загрузке пакета, о которой также следовало упомянуть.
Скорее всего, вам придется использовать 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)
Вы предпочитаете использовать
eval
, чем правильно настроенный проект TS? В вашем связанном комментарии этот подход называетсяquick and dirty
.