Skip to content

Commit 60d4d79

Browse files
committed
chore(repo): add ESM-only upgrade playbook for plugin packages\n\nRefs #1933
1 parent 18a4e38 commit 60d4d79

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Upgrade a plugin package to ESM-only (packages/<name>)
2+
3+
Upgrade a single plugin under `packages/<name>` to publish ESM-only output with TypeScript-emitted JS and declarations.
4+
5+
## Prerequisites
6+
7+
- Repo already contains shared config at `.config/tsconfig.base.json` and `.config/tsconfig.plugin.json` and (optionally) `.config/vitest.config.mts` from prior migrations.
8+
- Scope constraint: make changes only inside the target package directory (e.g., `packages/alias`). Do not add or edit files outside `packages/<name>`.
9+
- Local Node 20.19+ to run builds and tests.
10+
11+
## Steps
12+
13+
1. Identify the target package
14+
- Set a shell variable for reuse: `PKG=packages/<name>`.
15+
16+
2. Package metadata: ESM-only and minimums
17+
- Edit `$PKG/package.json`:
18+
- Set `"type": "module"`.
19+
- Replace legacy `main/module/exports.require` with ESM-only exports:
20+
```json
21+
"exports": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
22+
"types": "./dist/index.d.ts"
23+
```
24+
- Set minimums: `"engines": { "node": ">=20.19.0" }` and `"peerDependencies": { "rollup": ">=4.0.0" }`.
25+
- Keep `rollup` as a devDependency only if tests use it. Otherwise remove it.
26+
- Ensure published files include dist but exclude maps:
27+
```json
28+
"files": ["dist", "!dist/**/*.map", "README.md", "LICENSE"]
29+
```
30+
31+
3. Build scripts: TypeScript emit to dist
32+
- Prefer a tsc-only build for packages that do not need bundling:
33+
- In `$PKG/package.json`, set scripts:
34+
```json
35+
"prebuild": "del-cli dist",
36+
"build": "tsc --project tsconfig.json",
37+
"pretest": "pnpm build",
38+
"prerelease": "pnpm build",
39+
"prepare": "if [ ! -d 'dist' ]; then pnpm build; fi"
40+
```
41+
- If this package still needs bundling for tests/examples, keep its Rollup config but point inputs at the TypeScript output in `dist/` instead of sources.
42+
43+
4. TypeScript config: emit ESM to `dist/`
44+
- Create or update `$PKG/tsconfig.json` to extend the shared plugin config and emit declarations:
45+
```json
46+
{
47+
"extends": "../../.config/tsconfig.base.json",
48+
"compilerOptions": {
49+
"noEmit": false,
50+
"outDir": "dist",
51+
"rootDir": "src",
52+
"declaration": true,
53+
"declarationMap": true
54+
},
55+
"include": ["src/**/*"]
56+
}
57+
```
58+
- Delete any package-local `rollup` build scripts that produced CJS, and remove any `types/` folder if declarations were hand-authored (they will now be generated).
59+
60+
5. Source: convert to pure ESM and modern Node APIs
61+
- Replace `require`, `module.exports`, and `__dirname` patterns with ESM equivalents.
62+
- Use `node:` specifiers for built-ins (e.g., `import path from 'node:path'`).
63+
- Prefer URL utilities where needed (`fileURLToPath(new URL('.', import.meta.url))`).
64+
- Inline and export public types from `src/index.ts`; avoid separate `types/` unless unavoidable.
65+
66+
6. Tests: drop CJS branches; ESM everywhere
67+
- Remove CJS-specific branches/assertions from tests.
68+
- Keep the existing runner (AVA) if it already handles ESM in Node 20. If the package already uses Vitest in this repo, keep that pattern.
69+
- Ensure Rollup bundles created in tests are `await bundle.close()`-d to avoid leaks.
70+
71+
7. Clean up package artifacts
72+
- Remove obsolete files that are no longer used by ESM-only publishing (examples):
73+
- `$PKG/rollup.config.*` if switching to tsc-only.
74+
- `$PKG/types/**` once declarations are generated to `dist/`.
75+
76+
## Verify
77+
78+
- Build succeeds and emits JS and d.ts to `dist/`:
79+
```bash
80+
pnpm -C $PKG build
81+
tree $PKG/dist | sed -n '1,80p'
82+
```
83+
- Type declarations resolve for consumers:
84+
```bash
85+
jq -r '.types, .exports.types, .exports.import' $PKG/package.json
86+
```
87+
- Runtime smoke (Node ESM import works):
88+
```bash
89+
node -e "import('file://$PWD/$PKG/dist/index.js').then(() => console.log('ok'))"
90+
```
91+
- Tests pass for the package (runner may be AVA or Vitest depending on the package):
92+
```bash
93+
pnpm -C $PKG test
94+
```
95+
96+
## Rollback
97+
98+
- Revert the package directory to the previous commit:
99+
```bash
100+
git checkout -- $PKG
101+
git restore -SW $PKG
102+
```
103+
- If needed, `git reset --hard HEAD~1` when this package’s change is isolated on a feature branch.
104+
105+
## References
106+
107+
- Alias migration (ESM-only) — PR #1926: feat(alias)!: ESM only. Update Node and Rollup minimum versions
108+
- Task spec used for alias — Issue #1925
109+
- Shared TS configs used by packages — `.config/tsconfig.base.json`, `.config/tsconfig.plugin.json`

0 commit comments

Comments
 (0)