zshy 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  <p align="center">
2
2
 
3
- <h1 align="center">⚜️<br/><code>zshy</code></h1>
4
- <p align="center">The ultimate build tool for TypeScript libraries. Powered by <code>tsc</code>.
3
+ <h1 align="center">🐒<br/><code>zshy</code></h1>
4
+ <p align="center">The no-bundler build tool for TypeScript libraries. Powered by <code>tsc</code>.
5
5
  <br/>
6
6
  by <a href="https://x.com/colinhacks">@colinhacks</a>
7
7
  </p>
@@ -15,14 +15,14 @@
15
15
  <a href="https://github.com/colinhacks/zshy" rel="nofollow"><img src="https://img.shields.io/github/stars/colinhacks/zshy" alt="stars"></a>
16
16
  </p>
17
17
 
18
- <div align="center">
18
+ <!-- <div align="center">
19
19
  <a href="https://github.com/colinhacks/zshy">GitHub</a>
20
20
  <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
21
21
  <a href="https://twitter.com/colinhacks">𝕏</a>
22
22
  <span>&nbsp;&nbsp;•&nbsp;&nbsp;</span>
23
23
  <a href="https://bsky.app/profile/colinhacks.com">Bluesky</a>
24
24
  <br />
25
- </div>
25
+ </div> -->
26
26
 
27
27
  <br/>
28
28
  <br/>
@@ -34,6 +34,8 @@
34
34
 
35
35
  `zshy` is a simple, zero-config build tool for transpiling TypeScript libraries. It was originally created as internal build tool for [Zod](https://github.com/colinhacks/zod) but is now available as a general-purpose tool for TypeScript libraries.
36
36
 
37
+ <br/>
38
+
37
39
  ### Features
38
40
 
39
41
  - 🧱 **Dual-module builds** — Builds ESM and CJS outputs from a single TypeScript source file
@@ -49,8 +51,47 @@
49
51
  - 🐌 **Blazing fast** — Just kidding, it's slow. But [it's worth it](#is-it-fast).
50
52
 
51
53
  <br/>
54
+
52
55
  <br/>
53
- <h2 align="center">Usage</h2>
56
+ <br/>
57
+
58
+ <h2 align="center">How does it work?</h2>
59
+
60
+ Each `.ts` file is transpiled to `.js/.d.ts` (ESM) and `.cjs/.d.cts` (CommonJS).
61
+
62
+ ```bash
63
+ $ tree .
64
+ ├── package.json # if type == "module"
65
+ ├── src
66
+ │ └── index.ts
67
+ └── dist # generated
68
+ ├── index.js
69
+ ├── index.cjs
70
+ ├── index.d.ts
71
+ └── index.d.cts
72
+ ```
73
+
74
+ All relative `import`/`export` statements are rewritten to the appropriate extension during the build:
75
+
76
+ | Original path | Result (ESM) | Result (CJS) |
77
+ | ------------------ | ------------------ | ------------------- |
78
+ | `from "./util"` | `from "./util.js"` | `from "./util.cjs"` |
79
+ | `from "./util.ts"` | `from "./util.js"` | `from "./util.cjs"` |
80
+ | `from "./util.js"` | `from "./util.js"` | `from "./util.cjs"` |
81
+
82
+ Existing build tools (tsup, tsdown, etc) perform a similar transform during their bundling step. Unfortunately vanilla `tsc` [does not support extension rewriting](https://github.com/microsoft/TypeScript/issues/16577#issuecomment-754941937), leaving library authors with no choice but to use a bundler...
83
+
84
+ ...until now. `zshy` implements extension rewriting during the `tsc` build step via the official [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API) — specifically, the `ts.TransformerFactory` API for defining AST-level code transforms. This obviates the need for a bundler. The result is a tool that I consider to be the "holy grail" of TypeScript library build tools:
85
+
86
+ - performs dual-module (ESM + CJS) builds
87
+ - type checks your code
88
+ - leverages `tsc` for gold-standard transpilation
89
+ - doesn't require a bundler
90
+ - doesn't require another config file (just `package.json` and `tsconfig.json`)
91
+
92
+ <br/>
93
+ <br/>
94
+ <h2 align="center">Quickstart</h2>
54
95
 
55
96
  <br/>
56
97
 
@@ -83,30 +124,30 @@ Specify your package entrypoint with the `"zshy"` key in `package.json`.
83
124
  ```bash
84
125
  $ npx zshy
85
126
 
86
- 💎 Starting zshy build...
87
- ⚙️ Detected project root: /Users/colinmcd94/Documents/projects/zshy
88
- 📦 Reading package.json from ./package.json
89
- 📁 Reading tsconfig from ./tsconfig.json
90
- 🗑️ Cleaning up outDir...
91
- ➡️ Determining entrypoints...
127
+ Starting zshy build 🐒
128
+ Detected project root: /Users/colinmcd94/Documents/projects/zshy
129
+ Reading package.json from ./package.json
130
+ Reading tsconfig from ./tsconfig.json
131
+ Cleaning up outDir...
132
+ Determining entrypoints...
92
133
  ╔════════════╤════════════════╗
93
134
  ║ Subpath │ Entrypoint ║
94
135
  ╟────────────┼────────────────╢
95
136
  ║ "my-pkg" │ ./src/index.ts ║
96
137
  ╚════════════╧════════════════╝
97
- 🔧 Resolved build paths:
98
- ╔══════════╤═══════════════╗
99
- ║ Location │ Resolved path
100
- ╟──────────┼───────────────╢
101
- ║ rootDir │ ./src
102
- ║ outDir │ ./out
103
- ╚══════════╧═══════════════╝
104
- 🟨 Package is an ES module (package.json#/type is "module")
105
- 🧱 Building CJS... (rewriting .ts -> .cjs/.d.cts)
106
- 🧱 Building ESM...
107
- 📦 Updating package.json#/exports...
108
- 📦 Updating package.json#/bin...
109
- 🎉 Build complete!
138
+ Resolved build paths:
139
+ ╔══════════╤════════════════╗
140
+ ║ Location │ Resolved pathh
141
+ ╟──────────┼────────────────╢
142
+ ║ rootDir │ ./src
143
+ ║ outDir │ ./dist
144
+ ╚══════════╧════════════════╝
145
+ Package is an ES module (package.json#/type is "module")
146
+ Building CJS... (rewriting .ts -> .cjs/.d.cts)
147
+ Building ESM...
148
+ Updating package.json#/exports...
149
+ Updating package.json#/bin...
150
+ Build complete!
110
151
  ```
111
152
 
112
153
  Alernatively, add a `"build"` script to your `package.json`:
@@ -126,6 +167,26 @@ Then, to run a build:
126
167
  $ npm run build
127
168
  ```
128
169
 
170
+ <br/>
171
+ <br/>
172
+
173
+ <h2 align="center">Usage</h2>
174
+
175
+ <br/>
176
+
177
+ ### Flags
178
+
179
+ ```sh
180
+ $ npm zshy --help
181
+ Usage: zshy [options]
182
+
183
+ Options:
184
+ -h, --help Show this help message
185
+ -p, --project <path> Path to tsconfig (default: ./tsconfig.json)
186
+ --verbose Enable verbose output
187
+ --dry-run Don't write any files or update package.json
188
+ ```
189
+
129
190
  <br/>
130
191
 
131
192
  ### Subpaths and wildcards
@@ -150,16 +211,16 @@ Multi-entrypoint packages can specify subpaths or wildcard exports with `package
150
211
  <details>
151
212
  <summary>View typical build output</summary>
152
213
 
153
- When you run a build, you'll see something like this:
214
+ When you run a build, you'''ll see something like this:
154
215
 
155
216
  ```bash
156
217
  $ npx zshy
157
218
 
158
- 💎 Starting zshy build...
159
- ⚙️ Detected project root: /path/to/my-pkg
160
- 📦 Reading package.json from ./package.json
161
- 📁 Reading tsconfig from ./tsconfig.json
162
- ➡️ Determining entrypoints...
219
+ Starting zshy build... 🐒
220
+ Detected project root: /path/to/my-pkg
221
+ Reading package.json from ./package.json
222
+ Reading tsconfig from ./tsconfig.json
223
+ Determining entrypoints...
163
224
  ╔════════════════════╤═════════════════════════════╗
164
225
  ║ Subpath │ Entrypoint ║
165
226
  ╟────────────────────┼─────────────────────────────╢
@@ -167,18 +228,18 @@ $ npx zshy
167
228
  ║ "my-pkg/utils" │ ./src/utils.ts ║
168
229
  ║ "my-pkg/plugins/*" │ ./src/plugins/* (5 matches) ║
169
230
  ╚════════════════════╧═════════════════════════════╝
170
- 🔧 Resolved build paths:
171
- ╔══════════╤═══════════════╗
172
- ║ Location │ Resolved path
173
- ╟──────────┼───────────────╢
174
- ║ rootDir │ ./src
175
- ║ outDir │ ./out
176
- ╚══════════╧═══════════════╝
177
- 🟨 Package is ES module (package.json#/type is "module")
178
- 🧱 Building CJS... (rewriting .ts -> .cjs/.d.cts)
179
- 🧱 Building ESM...
180
- 📦 Updating package.json exports...
181
- 🎉 Build complete!
231
+ Resolved build paths:
232
+ ╔══════════╤════════════════╗
233
+ ║ Location │ Resolved pathh
234
+ ╟──────────┼────────────────╢
235
+ ║ rootDir │ ./src
236
+ ║ outDir │ ./dist
237
+ ╚══════════╧════════════════╝
238
+ Package is ES module (package.json#/type is "module")
239
+ Building CJS... (rewriting .ts -> .cjs/.d.cts)
240
+ Building ESM...
241
+ Updating package.json exports...
242
+ Build complete!
182
243
  ```
183
244
 
184
245
  And the generated `"exports"` map will look like this:
@@ -189,19 +250,19 @@ And the generated `"exports"` map will look like this:
189
250
  // ...
190
251
  + "exports": {
191
252
  + ".": {
192
- + "types": "./out/index.d.cts",
193
- + "import": "./out/index.js",
194
- + "require": "./out/index.cjs"
253
+ + "types": "./dist/index.d.cts",
254
+ + "import": "./dist/index.js",
255
+ + "require": "./dist/index.cjs"
195
256
  + },
196
257
  + "./utils": {
197
- + "types": "./out/utils.d.cts",
198
- + "import": "./out/utils.js",
199
- + "require": "./out/utils.cjs"
258
+ + "types": "./dist/utils.d.cts",
259
+ + "import": "./dist/utils.js",
260
+ + "require": "./dist/utils.cjs"
200
261
  + },
201
262
  + "./plugins/*": {
202
- + "types": "./out/src/plugins/*",
203
- + "import": "./out/src/plugins/*",
204
- + "require": "./out/src/plugins/*"
263
+ + "types": "./dist/src/plugins/*",
264
+ + "import": "./dist/src/plugins/*",
265
+ + "require": "./dist/src/plugins/*"
205
266
  + }
206
267
  + }
207
268
  }
@@ -211,15 +272,16 @@ And the generated `"exports"` map will look like this:
211
272
 
212
273
  <br/>
213
274
 
214
- ### For CLIs (`"bin"` support)
275
+ ### Building CLIs (`"bin"` support)
215
276
 
216
277
  If your package is a CLI, specify your CLI entrypoint in `package.json#/zshy/bin`. `zshy` will include this entrypoint in your builds and automatically set `"bin"` in your package.json.
217
278
 
218
- ```json
279
+ ```jsonc
219
280
  {
220
281
  // package.json
221
282
  "name": "my-cli",
222
283
  "version": "1.0.0",
284
+ "type": "module",
223
285
  "zshy": {
224
286
  "bin": "./src/cli.ts" // 👈 specify CLI entrypoint
225
287
  }
@@ -238,30 +300,17 @@ When you run `zshy`, it will automatically add the appropriate `"bin"` field to
238
300
  "bin": "./src/cli.ts"
239
301
  },
240
302
  + "bin": {
241
- + "my-cli": "./out/cli.js" // CLI entrypoint
303
+ + "my-cli": "./dist/cli.cjs" // CLI entrypoint
242
304
  + }
243
305
  }
244
306
  ```
245
307
 
246
308
  <br/>
247
309
 
248
- ### Flags
249
-
250
- ```sh
251
- $ npm zshy --help
252
- Usage: zshy [options]
253
-
254
- Options:
255
- -h, --help Show this help message
256
- -p, --project <path> Path to tsconfig.json file
257
- --verbose Enable verbose output
258
- --dry-run Don't write any files or update package.json
259
- ```
260
-
261
310
  <br/>
262
311
  <br/>
263
312
 
264
- <h2 align="center">FAQ</h2>
313
+ <h2 align="center">FAQ for nerds</h2>
265
314
 
266
315
  <br/>
267
316
 
@@ -392,7 +441,7 @@ Use whatever you like; `zshy` will rewrite all imports/exports properly during t
392
441
 
393
442
  <br/>
394
443
 
395
- ### How does it generate `package.json#/exports`?
444
+ ### What about `package.json#/exports`?
396
445
 
397
446
  Your exports map is automatically written into your `package.json` when you run `zshy`. The generated exports map looks like this:
398
447
 
@@ -407,18 +456,18 @@ Your exports map is automatically written into your `package.json` when you run
407
456
  },
408
457
  + "exports": { // auto-generated by zshy
409
458
  + ".": {
410
- + "types": "./out/index.d.cts",
411
- + "import": "./out/index.js",
412
- + "require": "./out/index.cjs"
459
+ + "types": "./dist/index.d.cts",
460
+ + "import": "./dist/index.js",
461
+ + "require": "./dist/index.cjs"
413
462
  + },
414
463
  + "./utils": {
415
- + "types": "./out/utils.d.cts",
416
- + "import": "./out/utils.js",
417
- + "require": "./out/utils.cjs"
464
+ + "types": "./dist/utils.d.cts",
465
+ + "import": "./dist/utils.js",
466
+ + "require": "./dist/utils.cjs"
418
467
  + },
419
468
  + "./plugins/*": {
420
- + "import": "./out/src/plugins/*",
421
- + "require": "./out/src/plugins/*"
469
+ + "import": "./dist/src/plugins/*",
470
+ + "require": "./dist/src/plugins/*"
422
471
  + }
423
472
  + }
424
473
  }
@@ -449,7 +498,7 @@ Yes! This is one of the key reasons `zshy` was originally developed. Many enviro
449
498
 
450
499
  - Node.js v12.7 or earlier
451
500
  - React Native - The Metro bundler does not support `"exports"` by default
452
- - TypeScript projects with legacy configs — e.. `"module": "commonjs"`
501
+ - TypeScript projects with legacy configs — e.g. `"module": "commonjs"`
453
502
 
454
503
  This causes issues for packages that want to use subpath imports to structure their package. Fortunately `zshy` unlocks a workaround I call a _flat build_:
455
504
 
@@ -458,12 +507,12 @@ This causes issues for packages that want to use subpath imports to structure th
458
507
  3. Set `outDir: "."` in your `tsconfig.json`
459
508
  4. Configure `"exclude"` in `package.json` to exclude all source files:
460
509
 
461
- - ```jsonc
462
- {
463
- // ...
464
- "exclude": ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts", "node_modules"]
465
- }
466
- ```
510
+ ```jsonc
511
+ {
512
+ // ...
513
+ "exclude": ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts", "node_modules"]
514
+ }
515
+ ```
467
516
 
468
517
  With this setup, your build outputs (`index.js`, etc) will be written to disk alongside to their corresponding source files. Older environments will resolve imports like `"your-library/utils"` to `"your-library/utils/index.js"`, effectively simulating subpath imports in environments that don't support them.
469
518
 
@@ -473,5 +522,5 @@ With this setup, your build outputs (`index.js`, etc) will be written to disk al
473
522
 
474
523
  Not really. It uses `tsc` to typecheck your codebase, which is a lot slower than using a bundler that strips types. That said:
475
524
 
476
- 1. you _should_ be type checking your code during builds;
525
+ 1. You _should_ be type checking your code during builds
477
526
  2. TypeScript is [about to get 10x faster](https://devblogs.microsoft.com/typescript/typescript-native-port/)