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
testscript to compile and run the output. I've put the following files into an empty directory (which I've namedso-70545129after the ID of this Stack Overflow question):Files
./package.json./tsconfig.json./src/index.tsNow, run
npm installand run thetestscript: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
importstatement into an invocation ofrequirebecause the module type is "CommonJS". Let's modify./src/index.tsto use dynamic import:Run the
testscript 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
requirestill in there? This GitHub issue ms/TS#43329 explains why TS still compiles this way, and offers two solutions:In your TSConfig, set
compilerOptions.moduleto"node12"(ornodenext).If #1 is not an option (you didn't say in your question), use
evalas a workaroundLet's explore both options:
Solution 1: Modify TSConfig
Let's modify the
compilerOptions.modulevalue 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
importinto 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
typescriptand reinstall the stable one:Then, modify the
compilerOptions.modulevalue back to"CommonJS"in./tsconfig.json:Solution 2: Workaround using
evalLet'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
evalso 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
importstatement wasn't transformed into arequirecall.Now, when you need to use the
unifiedfunction, just use this syntax in your program: