Skip to content

Commit 717134f

Browse files
committed
docs: add tsdown build migration design doc
1 parent 6e9ea72 commit 717134f

File tree

1 file changed

+84
-0
lines changed

1 file changed

+84
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# Design: Replace `tsc` Build with `tsdown`
2+
3+
Date: 2026-03-17 Status: Approved
4+
5+
## Problem
6+
7+
The published package is ~250KB, of which ~188KB is `dist/grammar.cjs` (104KB)
8+
and `dist/grammar.cjs.map` (84KB). The generated Peggy parser dominates the
9+
package size and its source map provides no value to consumers.
10+
11+
## Goal
12+
13+
Reduce published package size significantly by replacing `tsc` as the build tool
14+
with `tsdown`, which bundles all source into a single `dist/index.js`, inlines
15+
and minifies `grammar.cjs`, and generates a single source map covering only the
16+
hand-written TypeScript code.
17+
18+
## Approach
19+
20+
Replace `pnpm run build:entry` (`tsc --project tsconfig.build.json`) with
21+
`tsdown`. The grammar compilation step (`peggy`) is unchanged — it still runs
22+
first and produces `src/grammar.cjs`. tsdown then bundles everything starting
23+
from `src/index.ts`.
24+
25+
## tsdown Configuration (`tsdown.config.ts`)
26+
27+
```typescript
28+
import { defineConfig } from 'tsdown';
29+
30+
export default defineConfig({
31+
dts: true, // generate dist/index.d.ts (replaces tsc declaration output)
32+
entry: ['src/index.ts'],
33+
format: 'esm', // ESM-only, matching current package
34+
minify: true, // shrinks inlined grammar significantly
35+
platform: 'neutral', // works in Node.js and browsers
36+
sourcemap: true, // generates dist/index.js.map for hand-written code only
37+
// grammar is inlined — no separate grammar.cjs.map
38+
});
39+
```
40+
41+
## Changes to `package.json`
42+
43+
- Add `tsdown` to `devDependencies`
44+
- Replace `"build:entry": "tsc --project tsconfig.build.json"` with
45+
`"build:entry": "tsdown"`
46+
- `exports`, `main`, `types` fields stay unchanged — `dist/index.js` and
47+
`dist/index.d.ts` paths are the same
48+
49+
## Files to Remove
50+
51+
- `tsconfig.build.json` — no longer needed (tsdown reads `tsconfig.json`
52+
directly for type information)
53+
54+
## Expected Output
55+
56+
| File | Before | After |
57+
| ---------------------- | ---------- | ------------------------------------- |
58+
| `dist/grammar.cjs` | 104KB | gone (inlined) |
59+
| `dist/grammar.cjs.map` | 84KB | gone |
60+
| `dist/index.js` | ~4KB | ~35-45KB (inlined + minified grammar) |
61+
| `dist/index.js.map` | ~4KB | ~15-20KB |
62+
| `dist/index.d.ts` | ~4KB | ~4KB (unchanged) |
63+
| **Total** | **~250KB** | **~55-70KB** |
64+
65+
## What Stays the Same
66+
67+
- Public API — `import parse, { stringify, stream } from '@echecs/pgn'`
68+
- `exports` field in `package.json`
69+
- Grammar compilation — `pnpm grammar:compile` still runs first
70+
- Tests — `pnpm test` unchanged (vitest imports from `src/`, not `dist/`)
71+
- `prepare` script — still `pnpm run build`
72+
- `tsconfig.json` — still used for `lint:types` and type checking
73+
74+
## Testing the Build
75+
76+
After implementation, verify:
77+
78+
1. `pnpm build` succeeds
79+
2. `dist/index.js` exists and is minified
80+
3. `dist/index.d.ts` exists with correct type exports
81+
4. `dist/grammar.cjs.map` does not exist
82+
5. Published size: `npm pack --dry-run` shows significant reduction
83+
6. All 179 tests still pass (`pnpm test` uses `src/` directly, unaffected)
84+
7. Smoke test: the built `dist/index.js` can be imported and `parse()` works

0 commit comments

Comments
 (0)