How to configure TypeScript (tsconfig.json) in Node.js to work with ESModules inside node_modules?

1.1k Views Asked by At

I have a Node.js TypeScript project (AWS Lambda function) that has been working correctly for many months. However I recently needed to add the got package which is an ES Module and trying to run the transpiled project now results in:

require() of ES modules is not supported.
require() of *REDACTED*/node_modules/got/dist/source/index.js from *REDACTED*/my-lambda/handler/list-api.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.

This makes sense and looking inside nodemodules/got/package.json, the package is indeed an ES Module ("type": "module"). However, I was not able to come up with a version of tsconfig.json that would allow me to import this module AND not force me to update my app code in ugly ways (see below) or bundle it (which is obviously a problem for a lambda).

Could anyone please point me to a working tsconfig.json in a Node project that supports ES modules inside node_modules?

Original working version of my tsconfig.json

(before adding got and various attempts at fixing the problem)

{
  "compilerOptions": {
    "moduleResolution": "Node",
    "esModuleInterop": true,
    "noImplicitAny": true,
    "sourceMap": true,
    "outDir": "handler",
    "baseUrl": ".",
    "paths": {
      "*": ["node_modules/*"]
    },
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true
  },
  "include": ["src/**/*"]
}

One working "solution" is to convert my lambda into an ES module too ("type": "module" in package.json) and set "module" and "target" in tsconfig.json to esnext. This will functionally work, but is also forcing me to add .js suffixes into all relative imports in the project, which is really weird and difficult to read in TypeScript files. I also fear this might not work correctly in environments using older versions of Node.

Bundling with webpack and ts-loader works too, but obviously breaks Lambda's layer/handler separation.

Thanks a lot for any ideas!

1

There are 1 best solutions below

2
MinusFour On

Their README says this:

Warning: This package is native ESM and no longer provides a CommonJS export. If your project uses CommonJS, you'll have to convert to ESM or use the dynamic import() function. Please don't open issues for questions regarding CommonJS / ESM. You can also use Got v11 instead which is pretty stable.

You can import the module through import().

import('got').then((module) => {
  const { default: got } = module;
  /* same got as in         */
  /* import got from 'got'; */
  got.post(...) //etcetera
});

Or you can just use their last version that used cjs (11.0)

npm install got@11