141 lines
3.8 KiB
Markdown
141 lines
3.8 KiB
Markdown
[](https://github.com/Borewit/load-esm/actions/workflows/nodejs-ci.yml)
|
||
[](https://npmjs.org/package/load-esm)
|
||
[](https://npmcharts.com/compare/load-esm?start=365)
|
||
|
||
# load-esm
|
||
|
||
**load-esm** is a tiny utility that lets CommonJS (CJS) TypeScript projects **dynamically import pure ESM packages** at runtime—without hacks like `eval()`.
|
||
|
||
It helps avoid errors like:
|
||
|
||
* `Error [ERR_REQUIRE_ESM]: require() of ES Module`
|
||
* `Error [ERR_PACKAGE_PATH_NOT_EXPORTED]: No "exports" main defined in ...`
|
||
|
||
---
|
||
|
||
## Installation
|
||
|
||
```bash
|
||
npm install load-esm
|
||
# or
|
||
yarn add load-esm
|
||
# or
|
||
pnpm add load-esm
|
||
```
|
||
|
||
> Works in CJS TypeScript projects. No config changes required.
|
||
|
||
---
|
||
|
||
## Quick start
|
||
|
||
```ts
|
||
// TypeScript (CJS project)
|
||
import { loadEsm } from "load-esm";
|
||
|
||
(async () => {
|
||
const esmModule = await loadEsm("esm-module");
|
||
// use esmModule...
|
||
})();
|
||
```
|
||
|
||
### With typings
|
||
|
||
```ts
|
||
import { loadEsm } from "load-esm";
|
||
|
||
(async () => {
|
||
const esmModule = await loadEsm<typeof import("esm-module")>("esm-module");
|
||
// esmModule is fully typed
|
||
})();
|
||
```
|
||
|
||
### Concrete example (pure ESM package)
|
||
|
||
```ts
|
||
import { loadEsm } from "load-esm";
|
||
|
||
(async () => {
|
||
try {
|
||
// Import a pure ESM package from a CommonJS TS project
|
||
const { fileTypeFromFile } = await loadEsm<typeof import("file-type")>(
|
||
"file-type"
|
||
);
|
||
|
||
const type = await fileTypeFromFile("fixture.gif");
|
||
console.log(type);
|
||
} catch (error) {
|
||
console.error("Error importing module:", error);
|
||
}
|
||
})();
|
||
```
|
||
|
||
> Note: Because top‑level `await` isn’t available in CommonJS, examples use an async IIFE.
|
||
|
||
---
|
||
|
||
## API
|
||
|
||
```ts
|
||
function loadEsm<T = unknown>(name: string): Promise<T>
|
||
```
|
||
|
||
**Parameters**
|
||
|
||
* `name` — Package name or file path to import.
|
||
|
||
**Returns**
|
||
|
||
* `Promise<T>` resolving to the imported module namespace.
|
||
|
||
---
|
||
|
||
## How it works
|
||
|
||
In CJS TypeScript projects (`"module": "commonjs"`), the TS compiler transpiles dynamic `import()` to `require()`, which **breaks** when the target is a pure ESM package.
|
||
|
||
`load-esm` executes the `import()` **outside of TypeScript’s transpilation scope**, preserving native dynamic `import()` semantics at runtime. This keeps your code type‑safe while avoiding brittle workarounds (e.g., wrapping `import()` in `eval()`).
|
||
|
||
### What about Node.js ≥ 22.12?
|
||
|
||
Since Node.js 22.12, `require` can load **some** ESM modules, but there are [documented constraints](https://nodejs.org/api/modules.html#loading-ecmascript-modules-using-require). If your dependencies are compatible with that path, you might not need this utility. `load-esm` remains useful when:
|
||
|
||
* You’re on older Node.js versions that support `import()` (see Compatibility) but not the newer `require()` behavior.
|
||
* You want a single, consistent pattern that works across environments and avoids edge cases.
|
||
|
||
> If Node’s built‑in `require(esm)` works for your packages and version, feel free to use it.
|
||
|
||
---
|
||
|
||
## Compatibility
|
||
|
||
* **Node.js**: ≥ 13.2.0 (first version with native `import()` support)
|
||
* **TypeScript**: Fully typed; works in CJS projects.
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
* **`ERR_REQUIRE_ESM`**: Ensure you’re using `load-esm(...)` to import the ESM dependency from CJS code.
|
||
* **`No "exports" main defined`**: Some packages only expose ESM entry points. Import them via `load-esm`.
|
||
* **Type declarations**: Use the generic form `loadEsm<typeof import("pkg")>("pkg")` for typed access.
|
||
* **Top‑level await**: Wrap usage in an async IIFE in CJS.
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
[MIT](./LICENSE.txt)
|
||
|
||
---
|
||
|
||
### Changelog
|
||
|
||
See [Releases](https://github.com/Borewit/load-esm/releases).
|
||
|
||
---
|
||
|
||
### Acknowledgements
|
||
|
||
Inspired by common pain points when mixing CJS projects with modern ESM‑only libraries.
|