Use Pure ESM package in TypeScript project

Photo by Hakan Nural on Unsplash

Use Pure ESM package in TypeScript project


2 min read

When you write a Node.js application using TypeScript, the default configuraion will treat the ESM package as CommonJS package, just like this:

// before compile
import execa from 'execa'

// after compile
var execa_1 = require("execa");
(0, execa_1.execa)('openssl');

No errors are reported during compilation, but errors are reported at runtime:

Error [ERR_REQUIRE_ESM]: require() of ES Module not supported.

This article tell you how to configure your project to make pure ESM package work.

Configure TypeScript

open tsconfig.json in your project, set the compilerOptions.module to NodeNext , after this, js files generated by tsc/ts-node will use import instead of require.

However, since the default configuration of Node.js only supports synchronous module imports, TypeScript also takes this into account and does not compile the import statement, you will still get an error using the import statement, and you have to use dynamic imports, like this:

; (async () => {
    const { execa } = (await import('execa'))

It's terrible, but there is help, we just need to change the configuration of Node.js, and then TypeScript will see it and allow us to use the import statement.

Configure Node.js

The default configuration of Node.js also don't support ESM package, use import in .js file will throw errors:

import { execa } from 'execa'
(node:2164) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
SyntaxError: Cannot use import statement outside a module

The output of Node.js already indicates what we need to do, just open package.json and add a new property:

"type": "module"

Run it again and it works fine.

All done.