Skip to content

Commit 7f16b6a

Browse files
committed
initial commit
1 parent 0a3cb29 commit 7f16b6a

File tree

14 files changed

+2552
-0
lines changed

14 files changed

+2552
-0
lines changed

.editorconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
root = true
2+
3+
[*]
4+
indent_style = space
5+
indent_size = 2
6+
tab_width = 2
7+
end_of_line = lf
8+
charset = utf-8
9+
trim_trailing_whitespace = true
10+
insert_final_newline = true
11+
max_line_length = 120

.github/workflows/build.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Build and Lint
2+
3+
on:
4+
push:
5+
6+
env:
7+
PNPM_VERSION: '10'
8+
9+
jobs:
10+
build:
11+
name: 🏗️ Build
12+
runs-on: ubuntu-latest
13+
strategy:
14+
matrix:
15+
node-version: [20.x, 22.x]
16+
steps:
17+
- name: 🔄 Checkout sources
18+
uses: actions/checkout@v4
19+
- name: ⚙️ Use Node.js ${{ matrix.node-version }}
20+
uses: actions/setup-node@v4
21+
with:
22+
node-version: ${{ matrix.node-version }}
23+
- name: 📦 Install pnpm
24+
uses: pnpm/action-setup@v4
25+
with:
26+
version: ${{ env.PNPM_VERSION }}
27+
- name: 📌 Installing dependencies
28+
run: pnpm install --frozen-lockfile
29+
- name: 🛠️ Building sources
30+
run: pnpm run build
31+
32+
lint:
33+
name: 🔍 Lint Code
34+
needs: build
35+
runs-on: ubuntu-latest
36+
strategy:
37+
matrix:
38+
node-version: [ 20.x, 22.x ]
39+
steps:
40+
- name: 🔄 Checkout sources
41+
uses: actions/checkout@v4
42+
- name: ⚙️ Use Node.js ${{ matrix.node-version }}
43+
uses: actions/setup-node@v4
44+
with:
45+
node-version: ${{ matrix.node-version }}
46+
- name: 📦 Install pnpm
47+
uses: pnpm/action-setup@v4
48+
with:
49+
version: ${{ env.PNPM_VERSION }}
50+
- name: 📌 Installing dependencies
51+
run: pnpm install --frozen-lockfile
52+
- name: ✨ Linting
53+
run: pnpm run lint
54+
env:
55+
CI: true

.github/workflows/publish.yml

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
name: Publish
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*.*.*'
7+
8+
env:
9+
NODE_VERSION: '20.x'
10+
PNPM_VERSION: '10'
11+
12+
permissions:
13+
contents: read
14+
15+
jobs:
16+
build-and-test:
17+
name: 🏗️ Build and Test
18+
runs-on: ubuntu-latest
19+
steps:
20+
- name: 🔄 Checkout repository
21+
uses: actions/checkout@v4
22+
with:
23+
fetch-depth: 0
24+
25+
- name: ⚙️ Setup Node.js ${{ env.NODE_VERSION }}
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: ${{ env.NODE_VERSION }}
29+
30+
- name: 📦 Install pnpm
31+
uses: pnpm/action-setup@v4
32+
with:
33+
version: ${{ env.PNPM_VERSION }}
34+
35+
- name: 📌 Install dependencies
36+
run: pnpm install --frozen-lockfile
37+
38+
- name: 🛠️ Run build
39+
run: pnpm run build
40+
41+
- name: 🔍 Run lint
42+
run: pnpm run lint
43+
env:
44+
CI: true
45+
46+
publish-package:
47+
name: 🚀 Publish Package
48+
needs: build-and-test
49+
runs-on: ubuntu-latest
50+
permissions:
51+
contents: write
52+
steps:
53+
- name: 🔄 Checkout repository
54+
uses: actions/checkout@v4
55+
with:
56+
fetch-depth: 0
57+
58+
- name: ⚙️ Setup Node.js ${{ env.NODE_VERSION }}
59+
uses: actions/setup-node@v4
60+
with:
61+
node-version: ${{ env.NODE_VERSION }}
62+
registry-url: 'https://registry.npmjs.org'
63+
64+
- name: 📦 Install pnpm
65+
uses: pnpm/action-setup@v4
66+
with:
67+
version: ${{ env.PNPM_VERSION }}
68+
69+
- name: 🔖 Get and validate version
70+
id: version
71+
run: |
72+
if [[ $GITHUB_REF == refs/tags/v* ]]; then
73+
TAG_VERSION=${GITHUB_REF#refs/tags/v}
74+
echo "Using version from tag: $TAG_VERSION"
75+
CURRENT_VERSION=$(node -p "require('./package.json').version")
76+
77+
if [ "$TAG_VERSION" != "$CURRENT_VERSION" ]; then
78+
echo "Updating package version to match tag..."
79+
npm version $TAG_VERSION --no-git-tag-version
80+
pnpm install
81+
git config user.name "GitHub Actions"
82+
git config user.email "[email protected]"
83+
git add package.json pnpm-lock.yaml
84+
git commit -m "Update version to $TAG_VERSION [skip ci]"
85+
git push
86+
fi
87+
else
88+
TAG_VERSION=$(node -p "require('./package.json').version")
89+
echo "Using version from package.json: $TAG_VERSION"
90+
fi
91+
92+
echo "version=$TAG_VERSION" >> $GITHUB_OUTPUT
93+
echo "VERSION=$TAG_VERSION" >> $GITHUB_ENV
94+
env:
95+
GITHUB_TOKEN: ${{ secrets.PAT }}
96+
97+
- name: 📌 Install dependencies
98+
run: pnpm install --frozen-lockfile
99+
100+
- name: 🛠️ Build package
101+
run: pnpm run build
102+
103+
- name: 📤 Publish to NPM
104+
run: pnpm publish --no-git-checks
105+
env:
106+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.idea/
2+
node_modules/
3+
dist/
4+
5+
.DS_Store

.npmignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.idea/
2+
node_modules/
3+
4+
.editorconfig
5+
eslint.config.ts
6+
rollup.config.ts
7+
tsconfig.json

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Changelog
2+
3+
## [1.0.0] - Initial Release - 2025-05-09
4+
5+
### 🚀 Features
6+
7+
- **Initial implementation** of `rollup-plugin-esnext-to-nodenext`
8+
- Automatic transformation of ESM imports to Node.js-compatible format:
9+
- Converts `import { x } from "./file"` to `import { x } from "./file.js"`
10+
- Full TypeScript support
11+
- Automatic output directory detection from Rollup config
12+
13+
### ⚙️ Configuration Options
14+
15+
- `verbose`: Enable detailed logging (default: `false`)
16+
- `outputDir`: Manually specify output directory (optional)

README.md

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<div align="center">
2+
<h1>Rollup Plugin ESNext to NodeNext</h1>
3+
<a href="https://www.npmjs.com/package/rollup-plugin-esnext-to-nodenext" target="_blank" rel="noopener noreferrer"><img alt="NPM version" src="https://img.shields.io/npm/v/rollup-plugin-esnext-to-nodenext.svg?maxAge=3600&style=flat-square" /></a>
4+
<a href="https://www.npmjs.com/package/rollup-plugin-esnext-to-nodenext" target="_blank" rel="noopener noreferrer"><img alt="NPM downloads per month" src="https://img.shields.io/npm/dm/rollup-plugin-esnext-to-nodenext.svg?maxAge=3600&style=flat-square" /></a>
5+
<a href="https://github.com/mrrefactoring/rollup-plugin-esnext-to-nodenext" target="_blank" rel="noopener noreferrer"><img alt="build status" src="https://img.shields.io/github/actions/workflow/status/mrrefactoring/rollup-plugin-esnext-to-nodenext/.github/workflows/ci.yaml?branch=master&style=flat-square"></a>
6+
<a href="https://github.com/mrrefactoring/rollup-plugin-esnext-to-nodenext/blob/main/LICENSE" target="_blank" rel="noopener noreferrer"><img alt="license" src="https://img.shields.io/github/license/mrrefactoring/rollup-plugin-esnext-to-nodenext?color=green&style=flat-square"/></a>
7+
8+
<span>A Rollup plugin that transforms ESM imports to Node.js-compatible `nodenext` format by adding explicit file extensions.</span>
9+
</div>
10+
11+
## Features
12+
13+
- Automatically adds `.js` extensions to relative imports
14+
- Supports TypeScript and JavaScript files
15+
- Works with Rollup's output directory structure
16+
- Verbose logging option for debugging
17+
18+
## Installation
19+
20+
```bash
21+
npm install rollup-plugin-esnext-to-nodenext --save-dev
22+
```
23+
24+
```bash
25+
yarn add rollup-plugin-esnext-to-nodenext -D
26+
```
27+
28+
```bash
29+
pnpm add rollup-plugin-esnext-to-nodenext -D
30+
```
31+
32+
## Usage
33+
34+
```javascript
35+
import esnextToNodeNext from 'rollup-plugin-esnext-to-nodenext';
36+
import {defineConfig} from 'rollup';
37+
38+
export default defineConfig({
39+
input: 'src/index.ts',
40+
output: {
41+
file: 'dist/index.mjs',
42+
format: 'esm',
43+
sourcemap: true,
44+
},
45+
plugins: [
46+
esnextToNodeNext({
47+
verbose: true, // enable logging (optional)
48+
}),
49+
],
50+
});
51+
```
52+
53+
## Options
54+
55+
| Option | Type | Default | Description |
56+
|-------------|-----------|-----------------|--------------------------------------|
57+
| `verbose` | `boolean` | `false` | Enable detailed logging |
58+
| `outputDir` | `string` | *auto-detected* | Explicit output directory (optional) |
59+
60+
## How It Works
61+
62+
The plugin:
63+
64+
1. Detects your Rollup output directory automatically
65+
2. Processes all emitted files after bundling
66+
3. Transforms import statements like `from "./file"` to `from "./file.js"`
67+
4. Preserves all other bundling functionality
68+
69+
## Why Use This?
70+
71+
This plugin solves a specific compatibility problem when your project uses **TypeScript with `bundler` module resolution
72+
** during development, but needs to output **Node.js-compatible ESM with `nodenext` resolution** (particularly important
73+
for type declarations).
74+
75+
### Typical Use Case Example
76+
77+
Your `tsconfig.json` uses `bundler`-friendly settings:
78+
79+
```json
80+
{
81+
"compilerOptions": {
82+
"module": "esnext",
83+
"moduleResolution": "bundler",
84+
// ← Development mode (no .js extensions needed)
85+
"outDir": "dist"
86+
}
87+
}
88+
```
89+
90+
But your output needs to work with Node.js ESM (`nodenext`):
91+
92+
```json
93+
// package.json
94+
{
95+
"type": "module",
96+
"exports": {
97+
".": {
98+
"types": "./dist/index.d.ts",
99+
// ← Must be nodenext-compatible
100+
"import": "./dist/index.js"
101+
}
102+
}
103+
}
104+
```
105+
106+
The plugin bridges this gap by:
107+
108+
1. Taking Rollup's bundled output (no extensions)
109+
2. Transforming imports to be Node.js ESM-compliant:
110+
```diff
111+
- import { foo } from './utils';
112+
+ import { foo } from './utils.js';
113+
```
114+
3. Ensuring type declarations work in strict `nodenext` environments
115+
116+
### When You Need This
117+
118+
1. **Publishing libraries** with dual ESM/TypeScript support
119+
2. **Building CLI tools** that need strict Node.js ESM compliance
120+
3. **Generating type declarations** that must work in `nodenext` projects
121+
4. **Migrating codebases** from bundler-friendly to Node-native ESM
122+
123+
Without this transformation, you'll see Node.js errors like:
124+
125+
```
126+
Error [ERR_MODULE_NOT_FOUND]: Cannot find module './utils' imported from...
127+
Did you mean to import ./utils.js?
128+
```
129+
130+
## License
131+
132+
MIT © Vladislav Tupikin

0 commit comments

Comments
 (0)