TypeScript import @google-cloud/tasks error
Closed this issue ยท 5 comments
Since this change, import is broken from TypeScript with NodeNext
.
Code generating the error:
import { CloudTasksClient } from "@google-cloud/tasks";
Error message:
The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("@google-cloud/tasks")' call instead.
tsconfig.json:
{
"compilerOptions": {
"module": "NodeNext",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "ESNext"
},
"compileOnSave": true,
"include": [
"src"
]
}
Workaround 1: Downgrade to 4.0.1.
Workaround 2: Use dynamic import.
The Workaround 1 is posing another challenge. Fix for #5000 requires upgrading the @google-cloud/tasks to 5.2.1+, but you can't build it above 4.0.1. ๐
The reason for this is that @google-cloud/tasks is now published as a dual-format ESM and CJS module as of 5.0. Using NodeNext tells the compiler to import as ESM if you're using imports. One option is to use dynamic imports, like you said, or you can just require
tasks, it will use CJS.
@danielbankhead as FYI for future notes to better explain this feature.
I understand what is causing it, but the problem is that it's happening. None of the other @Google-Cloud packages have this problem (that I know of). @google-cloud/tasks didn't have this problem until recently either. A different design or way to export multiple format should be considered. I have started using dynamic imports as a workaround but regular import at the top of the file would be a much better option. Thank you.
The reason for this is that @google-cloud/tasks is now published as a dual-format ESM and CJS module as of 5.0. Using NodeNext tells the compiler to import as ESM if you're using imports. One option is to use dynamic imports, like you said, or you can just require tasks, it will use CJS.
This is not correct. Typescript resolves the import
for @google-cloud/tasks
to the cjs bundle because it is imported from a CommonJS context, so require
will be emitted in the compiled Javascript code if the error does not exist. Typescript is warning that we are require
ing the package because the cjs bundle looks like an ESM module on the Typescript side.
Reason that typescript misunderstands the module type is:
- Typescript considers
build/cjs/src/index.d.ts
as the entrypoint (it doesn't care that the corresponding Javascript file (build/cjs/src/index.cjs
) hascjs
extension) - Typescript infers the NodeFormat of
index.d.ts
to be ESM because the nearestpackage.json
has"type":"module"
in it.
So this can be resolved if we correctly tell the NodeFormat of build/cjs/src/index.d.ts
to Typescript. This can be done by one of the following:
- rename
index.d.ts
toindex.d.cts
- you have to rewrite the corresponding references in the
types
field and theexports
field of the package.json
- you have to rewrite the corresponding references in the
- place
package.json
with{"type":"commonjs"}
inbuild/cjs/src
- This might change the behavior of Node.js if some
.js
files exist underbuild/cjs/src
since it will no longer be treated as ESM
- This might change the behavior of Node.js if some