【问题标题】:Is there a way to combine ES6 imports and commonJS require in TS files?有没有办法在 TS 编译文件中结合 ES6 导入和 commonJS 要求?
【发布时间】:2022-05-05 06:23:54
【问题描述】:

我已将用 NodeJS 制作的项目的代码更改为 Typescript。 一切正常,除了显然第三方包(文件类型,https://www.npmjs.com/package/file-type)似乎不接受在编译的.js 文件中生成的require。 要改变这一点,我必须将 tsconfig.json 的“模块”属性更改为“commonjs”以外的另一个值。但是,它破坏了代码并产生了很多问题。

我的 tsconfig.json:

{
    "compilerOptions": {
        "target": "es6",
        "module": "commonjs",
        "allowJs": true,
        "lib": ["ES6"],
        "esModuleInterop": true,
        "moduleResolution": "node",
        "outDir": "build",
        "rootDir": "src",
        "skipLibCheck": true,
        "strict": true
    }
}

我得到的错误:

const filetype = __importStar(require("file-type"));
                              ^

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\user\Desktop\repos\art-api\node_modules\file-type\index.js from C:\Users\user\Desktop\repos\art-api\build\middlewares\process-image.js not supported.
Instead change the require of index.js in C:\Users\user\Desktop\repos\art-api\build\middlewares\process-image.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (C:\Users\user\Desktop\repos\art-api\build\middlewares\process-image.js:33:31)
    at Object.<anonymous> (C:\Users\user\Desktop\repos\art-api\build\controllers\artworkControllers.js:19:25)
    at Object.<anonymous> (C:\Users\user\Desktop\repos\art-api\build\routers\artworkRouter.js:7:30)
    at Object.<anonymous> (C:\Users\user\Desktop\repos\art-api\build\server.js:9:41) {
  code: 'ERR_REQUIRE_ESM'
}

显然,问题在于 JavaScript 中生成的代码与使用 ES6 导出语法的包的代码冲突。如果这是正确的,我该如何解决这个问题? 有没有办法只为这个特定的包生成带有导入语法的 .js 代码,或者类似的解决方法? 代码的其他部分没有给我任何问题,只有这个包的导入(文件类型)。

以防万一,这是“文件类型”的 index.js,其中包含编译器抱怨的导入:

import * as strtok3 from 'strtok3';
import {fileTypeFromTokenizer} from './core.js';

export async function fileTypeFromFile(path) {
    const tokenizer = await strtok3.fromFile(path);
    try {
        return await fileTypeFromTokenizer(tokenizer);
    } finally {
        await tokenizer.close();
    }
}

export * from './core.js';

【问题讨论】:

  • 我今天早些时候在尝试将npmjs.com/package/callsites 与打字稿一起使用时遇到了完全相同的问题,但无法找到解决方案。
  • FWIW,here 是关于同时使用 ESM 和 CommonJS 的 Node.js 文档。我不知道如何配置 TypeScript 来处理这个问题。
  • @axtck 我终于找到了解决方法,试试这个解决方案是否适合你
  • @wrongbyte 会看看!
  • "我已经将 NodeJS 中的项目代码更改为 Typescript。" - 你是说你有一个纯 JS 项目的工作版本吗?它使用了什么导入样式?

标签: javascript typescript


【解决方案1】:

简短回答:不;您将不得不选择 CommonJS 或 ES6 模块。

嗯,经过一些研究,我能够理解并解决问题。

关键是我使用的包,file-type,不向后兼容 CommonJS require() 语法。因此,在设置时

"module": "commonJS"

在我的tsconfig.json 文件中,等效的已编译javascript 文件将使用require();更具体地说,这样:

const file_type_1 = __importDefault(require("file-type"));

或一些变体,例如:

const filetype = __importStar(require("file-type"));

它与使用默认导出的 file-typeindex.js 文件冲突,正如您在随我的问题一起发布的代码中看到的那样。

所以,由于我打算继续使用这个包,我不得不更改文件的整个导入/导出系统,涉及以下步骤:

1 - 在 tsconfig.json 上将 "module": "commonJS" 更改为 "module": "ES6"

可能会导致“Cannot use import statement outside a module”等错误。发生这种情况是因为我们刚刚更改了已编译 .js 文件的语法,这些文件现在具有 import/export 语法,而不是 require()。 为了让 NodeJS 处理这个问题,我们必须遵循第二步:

2 - 在package.json上添加"type":"module"

3 - 更改相对导入的扩展

第二步将解决第一个问题,但是在导入文件时我们将不得不使用完整路径——即在相对导入上添加.js。所以,

import getImageRouter from './routers/imageRouter';

变成

import getImageRouter from './routers/imageRouter.js';

是的,尽管这看起来很奇怪,但我们在导入时使用了 .js 扩展名。Typescript 足够聪明,可以在编译期间为我们解决它。

这些步骤为我解决了这个问题。

进一步阅读的参考资料:

tsconfig.json 属性的精彩解释: https://medium.com/@tommedema/typescript-confusion-tsconfig-json-module-moduleresolution-target-lib-explained-65db2c44b491

Node.js 中的 ECMAScript 模块: https://www.typescriptlang.org/docs/handbook/esm-node.html

更多关于导入带有 .js 扩展名的文件: Appending .js extension on relative import statements during Typescript compilation (ES6 modules)

【讨论】:

    猜你喜欢
    • 2019-12-18
    • 2018-09-25
    • 2018-03-09
    • 1970-01-01
    • 2016-08-31
    • 2021-11-20
    • 1970-01-01
    • 2016-06-15
    • 1970-01-01
    相关资源
    最近更新 更多