Use of ESM-only (e.g. node-fetch 3.0.0) dependencies with TypeScript

I am using latest (Sep’21) versions of framework (2.59), typescript (4.4.3), and plugins (versions listed below)

I can make a trivial TS project working with serverless-plugin-typescript (2.0.0) and serverless-offline (8.2.0) – there are thousands of tutorials.

The problem starts when my handler imports node-fetch, i.e. uses ESM module imports. I tried all meaningful combinations of values for target, module, and other props in tsconfig.json (do not show it here as I am not referencing a particular combination). When I compile the project by running npx sls offline I can observe compiled version of my handler in dist (whatever is specified in tsconfig.json) folder, which either uses ESM or CJS to load node-fetch depending on how I set tsconfig.json file content. The code compiles fine and serverless-offline is ready to accept HTTP requests…

When a request is made to trigger the handler that uses node-fetch module I have one of two errors:

  1. require() of ES modules is not supported.Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: (when compiled code attempts to require package node-fetch)
  2. import fetch from 'node-fetch';SyntaxError: Cannot use import statement outside a module (when compiled code attempts to import package node-fetch).

I could be mistaken but my understanding is that errors are happening because internally my handler (responsible to handle HTTP request) are “loaded” with require (CJS) so runtime execution fails in first case above because I "require ESM module node-fetch" and it fails in the second case above because compiled version uses ESM exports which cannot be “understood” by CJS “require”

I spent days with this problem and I simply cannot believe it has no solution except to roll back to node-fetch 2.5.0 that uses CJS. Any thoughts?

1 Like