HUI*_*ANG 14 commonjs node.js typescript es6-modules
我正在开发一个依赖于仅 ESM 库的包:unified,并且我将我的 npm 包公开为 CommonJS 库。
当我在应用程序中调用我的包时,节点给出了以下错误消息:
不支持 ES 模块 node_modules\unified\index.js 的 require()
错误消息很明显,因为我们不允许使用require
ESM 模块,但我不是已经告诉 Typescript 将源代码编译为 CommonJS 格式吗?
参考:
jse*_*ksn 36
您不能在 CJS 中使用静态导入语句:没有办法解决它。
\n但是,如果您只需要在异步上下文中使用模块,则可以通过动态导入语句使用 ES 模块。然而,TypeScript 的当前状态给这种方法带来了一些复杂性。
\n考虑这个示例,其中我使用您提到的模块设置了 CJS TS 存储库,并且配置了 npmtest
脚本来编译和运行输出。我已将以下文件放入一个空目录(我so-70545129
以该 Stack Overflow 问题的 ID 命名):
./package.json
{\n "name": "so-70545129",\n "version": "1.0.0",\n "description": "",\n "type": "commonjs",\n "main": "dist/index.js",\n "scripts": {\n "compile": "tsc",\n "test": "npm run compile && node dist/index.js"\n },\n "author": "",\n "license": "MIT",\n "devDependencies": {\n "@types/node": "^17.0.5",\n "typescript": "^4.5.4"\n },\n "dependencies": {\n "unified": "^10.1.1"\n }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n./tsconfig.json
{\n "compilerOptions": {\n "exactOptionalPropertyTypes": true,\n "isolatedModules": true,\n "lib": [\n "ESNext"\n ],\n "module": "CommonJS",\n "moduleResolution": "Node",\n "noUncheckedIndexedAccess": true,\n "outDir": "dist",\n "strict": true,\n "target": "ESNext",\n },\n "include": [\n "./src/**/*"\n ]\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n./src/index.ts
import {unified} from \'unified\';\n\nfunction logUnified (): void {\n console.log(\'This is unified:\', unified);\n}\n\nlogUnified();\n\n
Run Code Online (Sandbox Code Playgroud)\n现在,运行npm install
并运行test
脚本:
$ npm install\n--- snip ---\n\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\n/so-70545129/dist/index.js:3\nconst unified_1 = require("unified");\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at Object.<anonymous> (/so-70545129/dist/index.js:3:19) {\n code: \'ERR_REQUIRE_ESM\'\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n作为参考,这里是输出./dist/index.js
::
$ npm install\n--- snip ---\n\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\n/so-70545129/dist/index.js:3\nconst unified_1 = require("unified");\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at Object.<anonymous> (/so-70545129/dist/index.js:3:19) {\n code: \'ERR_REQUIRE_ESM\'\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n上面的错误解释了问题(我在这个答案的顶部总结了这一问题)。TypeScript 已将静态import
语句转换为调用,require
因为模块类型是“CommonJS”。让我们修改./src/index.ts
为使用动态导入:
"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\nconst unified_1 = require("unified");\nfunction logUnified() {\n console.log(\'This is unified:\', unified_1.unified);\n}\nlogUnified();\n\n
Run Code Online (Sandbox Code Playgroud)\ntest
再次运行脚本:
$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\nnode:internal/process/promises:246\n triggerUncaughtException(err, true /* fromPromise */);\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at /so-70545129/dist/index.js:11:52\n at async getUnified (/so-70545129/dist/index.js:11:17)\n at async logUnified (/so-70545129/dist/index.js:16:21) {\n code: \'ERR_REQUIRE_ESM\'\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n嗯,我们不是刚刚解决了这个问题吗?让我们看一下输出./dist/index.js
::
import {type Processor} from \'unified\';\n\n/**\n * `unified` does not export the type of its main function,\n * but you can easily recreate it:\n *\n * Ref: https://github.com/unifiedjs/unified/blob/10.1.1/index.d.ts#L863\n */\ntype Unified = () => Processor;\n\n/**\n * AFAIK, all envs which support Node cache modules,\n * but, just in case, you can memoize it:\n */\nlet unified: Unified | undefined;\nasync function getUnified (): Promise<Unified> {\n if (typeof unified !== \'undefined\') return unified;\n const mod = await import(\'unified\');\n ({unified} = mod);\n return unified;\n}\n\nasync function logUnified (): Promise<void> {\n const unified = await getUnified();\n console.log(\'This is unified:\', unified);\n}\n\nlogUnified();\n\n
Run Code Online (Sandbox Code Playgroud)\n为什么呼叫require
仍然在那里?这个 GitHub 问题ms/TS#43329解释了为什么 TS 仍然以这种方式编译,并提供了两种解决方案:
在您的 TSConfig 中,设置compilerOptions.module
为"node12"
(或nodenext
)。
让我们探讨一下这两个选项:
\n让我们修改compilerOptions.module
一下中的值./tsconfig.json
:
$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\nnode:internal/process/promises:246\n triggerUncaughtException(err, true /* fromPromise */);\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at /so-70545129/dist/index.js:11:52\n at async getUnified (/so-70545129/dist/index.js:11:17)\n at async logUnified (/so-70545129/dist/index.js:16:21) {\n code: \'ERR_REQUIRE_ESM\'\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n并再次运行:
\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\ntsconfig.json:8:15 - error TS4124: Compiler option \'module\' of value \'node12\' is unstable. Use nightly TypeScript to silence this error. Try updating with \'npm install -D typescript@next\'.\n\n8 "module": "node12",\n ~~~~~~~~\n\n\nFound 1 error.\n\n
Run Code Online (Sandbox Code Playgroud)\n又一个编译器错误!让我们按照诊断消息中的建议来解决这个问题:将 TS 更新到不稳定版本typescript@next
:
$ npm uninstall typescript && npm install --save-dev typescript@next\n--- snip ---\n\n$ npm ls\nso-70545129@1.0.0 /so-70545129\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 @types/node@17.0.5\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 typescript@4.6.0-dev.20211231\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unified@10.1.1\n
Run Code Online (Sandbox Code Playgroud)\n\n\n现在安装的版本
\ntypescript
是"^4.6.0-dev.20211231"
让我们再次运行:
\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\nnode:internal/process/promises:246\n triggerUncaughtException(err, true /* fromPromise */);\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at /so-70545129/dist/index.js:30:65\n at async getUnified (/so-70545129/dist/index.js:30:17)\n at async logUnified (/so-70545129/dist/index.js:35:21) {\n code: \'ERR_REQUIRE_ESM\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n还是同样的错误。这是用于检查的输出./dist/index.js
::
"use strict";\nObject.defineProperty(exports, "__esModule", { value: true });\n/**\n * AFAIK, all envs which support Node cache modules,\n * but, just in case, you can memoize it:\n */\nlet unified;\nasync function getUnified() {\n if (typeof unified !== \'undefined\')\n return unified;\n const mod = await Promise.resolve().then(() => require(\'unified\'));\n ({ unified } = mod);\n return unified;\n}\nasync function logUnified() {\n const unified = await getUnified();\n console.log(\'This is unified:\', unified);\n}\nlogUnified();\n\n
Run Code Online (Sandbox Code Playgroud)\n尽管我们已遵循所有诊断消息建议并正确配置了项目,但TS 仍在将动态转换import
为对的调用。require
目前这似乎是一个错误。
让我们尝试一下解决方法,但首先,让我们撤消刚刚所做的更改:
\n首先,卸载不稳定版本typescript
并重新安装稳定版本:
$ npm uninstall typescript && npm install --save-dev typescript\n--- snip ---\n\n$ npm ls\nso-70545129@1.0.0 /so-70545129\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 @types/node@17.0.5\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 typescript@4.5.4\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unified@10.1.1\n
Run Code Online (Sandbox Code Playgroud)\n\n\n现在安装的版本
\ntypescript
是"^4.5.4"
然后,将compilerOptions.module
值修改回"CommonJS"
in ./tsconfig.json
:
{\n "compilerOptions": {\n ...\n "module": "node12",\n ...\n },\n...\n}\n\n
Run Code Online (Sandbox Code Playgroud)\neval
让我们修改./src/index.ts
,特别是函数getUnified
(第 16-21 行):
目前,它看起来像这样:
\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\ntsconfig.json:8:15 - error TS4124: Compiler option \'module\' of value \'node12\' is unstable. Use nightly TypeScript to silence this error. Try updating with \'npm install -D typescript@next\'.\n\n8 "module": "node12",\n ~~~~~~~~\n\n\nFound 1 error.\n\n
Run Code Online (Sandbox Code Playgroud)\n而TS拒绝停止变形的有问题的说法在第18行:
\n$ npm uninstall typescript && npm install --save-dev typescript@next\n--- snip ---\n\n$ npm ls\nso-70545129@1.0.0 /so-70545129\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 @types/node@17.0.5\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 typescript@4.6.0-dev.20211231\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unified@10.1.1\n
Run Code Online (Sandbox Code Playgroud)\n让我们将其移入字符串文字并在运行时使用它进行评估,eval
以便 TS 不会对其进行转换:
$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\nnode:internal/process/promises:246\n triggerUncaughtException(err, true /* fromPromise */);\n ^\n\nError [ERR_REQUIRE_ESM]: require() of ES Module /so-70545129/node_modules/unified/index.js from /so-70545129/dist/index.js not supported.\nInstead change the require of /so-70545129/node_modules/unified/index.js in /so-70545129/dist/index.js to a dynamic import() which is available in all CommonJS modules.\n at /so-70545129/dist/index.js:30:65\n at async getUnified (/so-70545129/dist/index.js:30:17)\n at async logUnified (/so-70545129/dist/index.js:35:21) {\n code: \'ERR_REQUIRE_ESM\'\n}\n
Run Code Online (Sandbox Code Playgroud)\n所以整个函数现在看起来像这样:
\n"use strict";\nvar __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\n}) : (function(o, m, k, k2) {\n if (k2 === undefined) k2 = k;\n o[k2] = m[k];\n}));\nvar __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {\n Object.defineProperty(o, "default", { enumerable: true, value: v });\n}) : function(o, v) {\n o["default"] = v;\n});\nvar __importStar = (this && this.__importStar) || function (mod) {\n if (mod && mod.__esModule) return mod;\n var result = {};\n if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\n __setModuleDefault(result, mod);\n return result;\n};\nObject.defineProperty(exports, "__esModule", { value: true });\n/**\n * AFAIK, all envs which support Node cache modules,\n * but, just in case, you can memoize it:\n */\nlet unified;\nasync function getUnified() {\n if (typeof unified !== \'undefined\')\n return unified;\n const mod = await Promise.resolve().then(() => __importStar(require(\'unified\')));\n ({ unified } = mod);\n return unified;\n}\nasync function logUnified() {\n const unified = await getUnified();\n console.log(\'This is unified:\', unified);\n}\nlogUnified();\n\n
Run Code Online (Sandbox Code Playgroud)\n保存文件并再次运行:
\n$ npm run test\n\n> so-70545129@1.0.0 test\n> npm run compile && node dist/index.js\n\n\n> so-70545129@1.0.0 compile\n> tsc\n\nThis is unified: [Function: processor] {\n data: [Function: data],\n Parser: undefined,\n Compiler: undefined,\n freeze: [Function: freeze],\n attachers: [],\n use: [Function: use],\n parse: [Function: parse],\n stringify: [Function: stringify],\n run: [Function: run],\n runSync: [Function: runSync],\n process: [Function: process],\n processSync: [Function: processSync]\n}\n
Run Code Online (Sandbox Code Playgroud)\n最后!达到了预期的结果。让我们最后一次比较一下输出./dist/index.js
::
$ npm uninstall typescript && npm install --save-dev typescript\n--- snip ---\n\n$ npm ls\nso-70545129@1.0.0 /so-70545129\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 @types/node@17.0.5\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 typescript@4.5.4\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 unified@10.1.1\n
Run Code Online (Sandbox Code Playgroud)\n这就是我们想要的:动态import
语句没有转换为require
调用。
现在,当您需要使用该unified
函数时,只需在程序中使用以下语法:
{\n "compilerOptions": {\n ...\n "module": "CommonJS",\n ...\n },\n...\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n
我们在尝试导入仅 ESM 的包 (ChatGPT) 时遇到了这个问题,甚至尝试动态失败,因为import
已被转译。我们在这个文件中找到了解决方案:
export const importDynamic = new Function('modulePath', 'return import(modulePath)');
async function fn {
// use the dynamic import:
const { ChatGPTAPI } = await importDynamic('chatgpt');
// do whatever you need to do:
api = new ChatGPTAPI();
}
Run Code Online (Sandbox Code Playgroud)
进一步思考,它所做的似乎只是使用 Javascript 的能力来评估基于字符串的函数,因此转译器无法触及它。天才!
归档时间: |
|
查看次数: |
19116 次 |
最近记录: |