I am working on a package that depends on a ESM only library: unified and I exposed my npm package as CommonJS library.
When I called my package in an application, node gives me this error message:
require() of ES Module node_modules\unified\index.js not supported
The error message is obvious since we are not allowed to require
a ESM module, but didn't I already tell Typescript to compile the source code into CommonJS format?
References:
Summary
You can't use static import statements in CJS: there's no way around it.
However it is possible to use ES modules via dynamic import statements if you only need to use the module in async contexts. However, the current state of TypeScript introduces some complexity in regard to this approach.
How-to
Consider this example in which I've setup a CJS TS repo using the module you mentioned, and I've configured the npm
test
script to compile and run the output. I've put the following files into an empty directory (which I've namedso-70545129
after the ID of this Stack Overflow question):Files
./package.json
./tsconfig.json
./src/index.ts
Now, run
npm install
and run thetest
script:For reference, here's the output:
./dist/index.js
:The error above explains the problem (which I summarized at the top of this answer). TypeScript has transformed the static
import
statement into an invocation ofrequire
because the module type is "CommonJS". Let's modify./src/index.ts
to use dynamic import:Run the
test
script again:Roadblock
Hmm , didn't we just fix this?? Let's take a look at the output:
./dist/index.js
:Solutions
Why is the call to
require
still in there? This GitHub issue ms/TS#43329 explains why TS still compiles this way, and offers two solutions:In your TSConfig, set
compilerOptions.module
to"node12"
(ornodenext
).If #1 is not an option (you didn't say in your question), use
eval
as a workaroundLet's explore both options:
Solution 1: Modify TSConfig
Let's modify the
compilerOptions.module
value in./tsconfig.json
:And run again:
Another compiler error! Let's address it by following the suggestion in the diagnostic message: updating TS to the unstable version
typescript@next
:Let's run again:
Still the same error. Here's the output for examination:
./dist/index.js
:TS is still transforming the dynamic
import
into a call torequire
, even though we've followed all diagnostic message suggestions, and configured the project correctly. This seems like a bug at this point.Let's try the workaround instead, but first, let's undo the changes we just made:
First, uninstall the unstable version of
typescript
and reinstall the stable one:Then, modify the
compilerOptions.module
value back to"CommonJS"
in./tsconfig.json
:Solution 2: Workaround using
eval
Let's modify
./src/index.ts
, specifically the functiongetUnified
(lines 16-21):Currently, it looks like this:
and the problematic statement that TS refuses to stop transforming is on line 18:
Let's move this into a string literal and evaluate it at runtime using
eval
so that TS will not transform it:So the entire function now looks like this:
Save the file and run again:
Finally! The desired result is achieved. Let's compare the output one last time:
./dist/index.js
:That's what we wanted: the dynamic
import
statement wasn't transformed into arequire
call.Now, when you need to use the
unified
function, just use this syntax in your program: