A Rollup plugin that transforms ESM imports to Node.js-compatible nodenext
format by adding explicit file extensions.
- Automatically adds
.js
extensions to relative imports - Supports TypeScript and JavaScript files
- Works with Rollup's output directory structure
- Verbose logging option for debugging
npm install rollup-plugin-esnext-to-nodenext --save-dev
yarn add rollup-plugin-esnext-to-nodenext -D
pnpm add rollup-plugin-esnext-to-nodenext -D
import esnextToNodeNext from 'rollup-plugin-esnext-to-nodenext';
import {defineConfig} from 'rollup';
export default defineConfig({
input: 'src/index.ts',
output: {
file: 'dist/index.mjs',
format: 'esm',
sourcemap: true,
},
plugins: [
esnextToNodeNext({
verbose: true, // enable logging (optional)
}),
],
});
Option | Type | Default | Description |
---|---|---|---|
verbose |
boolean |
false |
Enable detailed logging |
outputDir |
string |
auto-detected | Explicit output directory (optional) |
The plugin:
- Detects your Rollup output directory automatically
- Processes all emitted files after bundling
- Transforms import statements like
from "./file"
tofrom "./file.js"
- Preserves all other bundling functionality
This plugin solves a specific compatibility problem when your project uses **TypeScript with bundler
module resolution
** during development, but needs to output Node.js-compatible ESM with nodenext
resolution (particularly important
for type declarations).
Your tsconfig.json
uses bundler
-friendly settings:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler",
// ← Development mode (no .js extensions needed)
"outDir": "dist"
}
}
But your output needs to work with Node.js ESM (nodenext
):
// package.json
{
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
// ← Must be nodenext-compatible
"import": "./dist/index.js"
}
}
}
The plugin bridges this gap by:
- Taking Rollup's bundled output (no extensions)
- Transforming imports to be Node.js ESM-compliant:
- import { foo } from './utils'; + import { foo } from './utils.js';
- Ensuring type declarations work in strict
nodenext
environments
- Publishing libraries with dual ESM/TypeScript support
- Building CLI tools that need strict Node.js ESM compliance
- Generating type declarations that must work in
nodenext
projects - Migrating codebases from bundler-friendly to Node-native ESM
Without this transformation, you'll see Node.js errors like:
Error [ERR_MODULE_NOT_FOUND]: Cannot find module './utils' imported from...
Did you mean to import ./utils.js?
MIT © Vladislav Tupikin