zshy 0.0.5 → 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 +257 -87
- package/dist/index.cjs +697 -0
- package/dist/index.js +659 -0
- package/{out → dist}/utils.cjs +33 -38
- package/{out → dist}/utils.d.cts +6 -1
- package/{out → dist}/utils.d.ts +6 -1
- package/{out → dist}/utils.js +31 -38
- package/package.json +19 -30
- package/out/index.cjs +0 -481
- package/out/index.js +0 -443
- package/out/plugins/a.cjs +0 -4
- package/out/plugins/a.d.cts +0 -1
- package/out/plugins/a.d.ts +0 -1
- package/out/plugins/a.js +0 -1
- package/out/plugins/b.cjs +0 -4
- package/out/plugins/b.d.cts +0 -1
- package/out/plugins/b.d.ts +0 -1
- package/out/plugins/b.js +0 -1
- /package/{out → dist}/index.d.cts +0 -0
- /package/{out → dist}/index.d.ts +0 -0
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
|
|
3
|
-
<h1 align="center"
|
|
4
|
-
<p align="center">
|
|
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,42 +15,83 @@
|
|
|
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> • </span>
|
|
21
21
|
<a href="https://twitter.com/colinhacks">𝕏</a>
|
|
22
22
|
<span> • </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/>
|
|
29
29
|
<br/>
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
<!-- ## What is `zshy`? -->
|
|
33
32
|
|
|
34
33
|
<h2 align="center">What is <code>zshy</code>?</h2>
|
|
35
34
|
|
|
36
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.
|
|
37
36
|
|
|
37
|
+
<br/>
|
|
38
|
+
|
|
38
39
|
### Features
|
|
39
40
|
|
|
40
41
|
- 🧱 **Dual-module builds** — Builds ESM and CJS outputs from a single TypeScript source file
|
|
41
42
|
- 👑 **Powered by `tsc`** — No bundling, no extra configs, just good old-fashioned `tsc`
|
|
42
|
-
-
|
|
43
|
+
- 🟦 **No config file** — Reads only from your `package.json` and `tsconfig.json` (configurable)
|
|
44
|
+
- 📝 **Declarative entrypoint map** — Specify your TypeScript entrypoints in `package.json#/zshy`
|
|
43
45
|
- 🤖 **Auto-generated `"exports"`** — Writes `"exports"` map directly into your `package.json`
|
|
44
|
-
-
|
|
45
|
-
- 📂 **
|
|
46
|
-
- 🔗 **
|
|
47
|
-
- ⚛️ **Supports `.tsx`**
|
|
48
|
-
- 📱 **Supports React Native**
|
|
49
|
-
- 🐌 **Blazing fast** — Just kidding, it's slow. But
|
|
46
|
+
- 🐚 **CLI-friendly** — First-class `"bin"` support
|
|
47
|
+
- 📂 **Supports any file structure** — Use any file structure you like
|
|
48
|
+
- 🔗 **Supports extensionless imports** — Use any import syntax TypeScript supports: extensionless, `.js`, `.ts`
|
|
49
|
+
- ⚛️ **Supports `.tsx`** — Rewrites to `.js/.cjs/.mjs` per your `tsconfig.json#/jsx*` settings
|
|
50
|
+
- 📱 **Supports React Native** — Supports a [flat build mode](#can-it-support-react-native-legacy-or-non-nodejs-environments) designed for bundlers that don't support `package.json#/exports`
|
|
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
|
-
<
|
|
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
|
|
|
@@ -72,11 +113,85 @@ Specify your package entrypoint with the `"zshy"` key in `package.json`.
|
|
|
72
113
|
{
|
|
73
114
|
"name": "my-pkg",
|
|
74
115
|
"version": "1.0.0",
|
|
75
|
-
"zshy": "./src/index.ts" // package entrypoint
|
|
116
|
+
"zshy": "./src/index.ts" // 👈 package entrypoint
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
<br/>
|
|
121
|
+
|
|
122
|
+
### 3. Run a build
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
$ npx zshy
|
|
126
|
+
|
|
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...
|
|
133
|
+
╔════════════╤════════════════╗
|
|
134
|
+
║ Subpath │ Entrypoint ║
|
|
135
|
+
╟────────────┼────────────────╢
|
|
136
|
+
║ "my-pkg" │ ./src/index.ts ║
|
|
137
|
+
╚════════════╧════════════════╝
|
|
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! ✅
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Alernatively, add a `"build"` script to your `package.json`:
|
|
154
|
+
|
|
155
|
+
```diff
|
|
156
|
+
{
|
|
157
|
+
// ...
|
|
158
|
+
"scripts": {
|
|
159
|
+
+ "build": "zshy"
|
|
160
|
+
}
|
|
76
161
|
}
|
|
77
162
|
```
|
|
78
163
|
|
|
79
|
-
|
|
164
|
+
Then, to run a build:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
$ npm run build
|
|
168
|
+
```
|
|
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
|
+
|
|
190
|
+
<br/>
|
|
191
|
+
|
|
192
|
+
### Subpaths and wildcards
|
|
193
|
+
|
|
194
|
+
Multi-entrypoint packages can specify subpaths or wildcard exports with `package.json#/zshy/exports`:
|
|
80
195
|
|
|
81
196
|
```jsonc
|
|
82
197
|
{
|
|
@@ -93,78 +208,115 @@ More complicated packages can specify subpaths or wildcard exports with `"zshy.e
|
|
|
93
208
|
}
|
|
94
209
|
```
|
|
95
210
|
|
|
96
|
-
<
|
|
211
|
+
<details>
|
|
212
|
+
<summary>View typical build output</summary>
|
|
97
213
|
|
|
98
|
-
|
|
214
|
+
When you run a build, you'''ll see something like this:
|
|
99
215
|
|
|
100
216
|
```bash
|
|
101
217
|
$ npx zshy
|
|
102
218
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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...
|
|
108
224
|
╔════════════════════╤═════════════════════════════╗
|
|
109
225
|
║ Subpath │ Entrypoint ║
|
|
110
226
|
╟────────────────────┼─────────────────────────────╢
|
|
111
227
|
║ "my-pkg" │ ./src/index.ts ║
|
|
112
|
-
╟────────────────────┼─────────────────────────────╢
|
|
113
228
|
║ "my-pkg/utils" │ ./src/utils.ts ║
|
|
114
|
-
╟────────────────────┼─────────────────────────────╢
|
|
115
229
|
║ "my-pkg/plugins/*" │ ./src/plugins/* (5 matches) ║
|
|
116
230
|
╚════════════════════╧═════════════════════════════╝
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"types": "./out/utils.d.cts",
|
|
130
|
-
"import": "./out/utils.js",
|
|
131
|
-
"require": "./out/utils.cjs"
|
|
132
|
-
},
|
|
133
|
-
"./plugins/*": {
|
|
134
|
-
"import": "./out/src/plugins/*",
|
|
135
|
-
"require": "./out/src/plugins/*"
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
🎉 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! ✅
|
|
139
243
|
```
|
|
140
244
|
|
|
141
|
-
|
|
245
|
+
And the generated `"exports"` map will look like this:
|
|
142
246
|
|
|
143
247
|
```diff
|
|
248
|
+
// package.json
|
|
144
249
|
{
|
|
145
250
|
// ...
|
|
146
|
-
|
|
147
|
-
+ "
|
|
251
|
+
+ "exports": {
|
|
252
|
+
+ ".": {
|
|
253
|
+
+ "types": "./dist/index.d.cts",
|
|
254
|
+
+ "import": "./dist/index.js",
|
|
255
|
+
+ "require": "./dist/index.cjs"
|
|
256
|
+
+ },
|
|
257
|
+
+ "./utils": {
|
|
258
|
+
+ "types": "./dist/utils.d.cts",
|
|
259
|
+
+ "import": "./dist/utils.js",
|
|
260
|
+
+ "require": "./dist/utils.cjs"
|
|
261
|
+
+ },
|
|
262
|
+
+ "./plugins/*": {
|
|
263
|
+
+ "types": "./dist/src/plugins/*",
|
|
264
|
+
+ "import": "./dist/src/plugins/*",
|
|
265
|
+
+ "require": "./dist/src/plugins/*"
|
|
266
|
+
+ }
|
|
267
|
+
+ }
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
</details>
|
|
272
|
+
|
|
273
|
+
<br/>
|
|
274
|
+
|
|
275
|
+
### Building CLIs (`"bin"` support)
|
|
276
|
+
|
|
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.
|
|
278
|
+
|
|
279
|
+
```jsonc
|
|
280
|
+
{
|
|
281
|
+
// package.json
|
|
282
|
+
"name": "my-cli",
|
|
283
|
+
"version": "1.0.0",
|
|
284
|
+
"type": "module",
|
|
285
|
+
"zshy": {
|
|
286
|
+
"bin": "./src/cli.ts" // 👈 specify CLI entrypoint
|
|
148
287
|
}
|
|
149
288
|
}
|
|
150
289
|
```
|
|
151
290
|
|
|
152
|
-
|
|
291
|
+
When you run `zshy`, it will automatically add the appropriate `"bin"` field to your `package.json`:
|
|
153
292
|
|
|
154
|
-
```
|
|
155
|
-
|
|
293
|
+
```diff
|
|
294
|
+
{
|
|
295
|
+
// package.json
|
|
296
|
+
"name": "my-cli",
|
|
297
|
+
"version": "1.0.0",
|
|
298
|
+
"zshy": {
|
|
299
|
+
"exports": "./src/index.ts",
|
|
300
|
+
"bin": "./src/cli.ts"
|
|
301
|
+
},
|
|
302
|
+
+ "bin": {
|
|
303
|
+
+ "my-cli": "./dist/cli.cjs" // CLI entrypoint
|
|
304
|
+
+ }
|
|
305
|
+
}
|
|
156
306
|
```
|
|
157
307
|
|
|
308
|
+
<br/>
|
|
158
309
|
|
|
159
310
|
<br/>
|
|
160
311
|
<br/>
|
|
161
|
-
|
|
312
|
+
|
|
313
|
+
<h2 align="center">FAQ for nerds</h2>
|
|
162
314
|
|
|
163
315
|
<br/>
|
|
164
316
|
|
|
165
317
|
### How does `zshy` resolve entrypoints?
|
|
166
318
|
|
|
167
|
-
It reads your `package.json
|
|
319
|
+
It reads your `package.json#/zshy` config:
|
|
168
320
|
|
|
169
321
|
```jsonc
|
|
170
322
|
// package.json
|
|
@@ -214,72 +366,82 @@ No. You can organize your source however you like; `zshy` will transpile your en
|
|
|
214
366
|
|
|
215
367
|
### What files does `zshy` create?
|
|
216
368
|
|
|
217
|
-
It depends on your `package.json
|
|
369
|
+
It depends on your `package.json#/type` field. If your package is ESM (that is, `"type": "module"` in `package.json`):
|
|
218
370
|
|
|
219
371
|
- `.js` + `.d.ts` (ESM)
|
|
220
372
|
- `.cjs` + `.d.cts` (CJS)
|
|
221
373
|
|
|
222
374
|
```bash
|
|
223
|
-
$ tree
|
|
375
|
+
$ tree dist
|
|
224
376
|
|
|
225
377
|
.
|
|
226
378
|
├── package.json # if type == "module"
|
|
227
379
|
├── src
|
|
228
380
|
│ └── index.ts
|
|
229
|
-
└──
|
|
230
|
-
├── index.js
|
|
381
|
+
└── dist
|
|
382
|
+
├── index.js
|
|
231
383
|
├── index.d.ts
|
|
232
384
|
├── index.cts
|
|
233
385
|
└── index.d.cts
|
|
234
386
|
```
|
|
235
387
|
|
|
236
|
-
Otherwise, the package is considered
|
|
388
|
+
Otherwise, the package is considered _default-CJS_ and the ESM build files will be rewritten as `.mjs`/`.d.mts`.
|
|
237
389
|
|
|
238
390
|
- `.mjs` + `.d.mts` (ESM)
|
|
239
391
|
- `.js` + `.d.ts` (CJS)
|
|
240
392
|
|
|
241
393
|
```bash
|
|
242
|
-
$ tree
|
|
394
|
+
$ tree dist
|
|
243
395
|
.
|
|
244
396
|
├── package.json # if type != "module"
|
|
245
397
|
├── src
|
|
246
398
|
│ └── index.ts
|
|
247
|
-
└──
|
|
399
|
+
└── dist
|
|
248
400
|
├── index.js
|
|
249
401
|
├── index.d.ts
|
|
250
402
|
├── index.mjs
|
|
251
403
|
└── index.d.mts
|
|
252
404
|
```
|
|
253
405
|
|
|
254
|
-
> **Comparison** — `tshy` generates plain `.js`/`.d.ts` files into separate `dist/esm` and `dist/cjs` directories, each with a stub `package.json` to enable proper module resolution in Node.js. This is more convoluted than the flat file structure generated by `zshy`. It also causes issues with [Module Federation](https://github.com/colinhacks/zod/issues/4656).
|
|
406
|
+
> **Comparison** — `tshy` generates plain `.js`/`.d.ts` files into separate `dist/esm` and `dist/cjs` directories, each with a stub `package.json` to enable proper module resolution in Node.js. This is more convoluted than the flat file structure generated by `zshy`. It also causes issues with [Module Federation](https://github.com/colinhacks/zod/issues/4656).
|
|
255
407
|
|
|
256
408
|
<br/>
|
|
257
409
|
|
|
258
410
|
### How does extension rewriting work?
|
|
259
411
|
|
|
260
|
-
`zshy` uses the [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API) to
|
|
412
|
+
`zshy` uses the [TypeScript Compiler API](https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API) to rewrite file extensions during the `tsc` build process. This makes it possible to generate CJS and ESM build outputs side-by-side.
|
|
413
|
+
|
|
414
|
+
Depending on the build format being targeted, `zshy` will:
|
|
415
|
+
|
|
416
|
+
- Rewrite `.ts` imports/exports to `.js`/`.cjs`/`.mjs`
|
|
417
|
+
- Rewrite extensionless imports/exports to `.js`/`.cjs`/`.mjs`
|
|
418
|
+
- Rewrite `.js` imports/exports to `.cjs`/`.mjs`
|
|
419
|
+
- Rename build output files to `.cjs`/`.mjs`/`.d.cts`/`.d.mts`
|
|
420
|
+
|
|
421
|
+
TypeScript provides dedicated hooks for performing such transforms (though they are criminally under-utilized).
|
|
261
422
|
|
|
262
423
|
- **`ts.TransformerFactory`**: Provides AST transformations to rewrite import/export extensions before module conversion
|
|
263
424
|
- **`ts.CompilerHost#writeFile`**: Handles output file extension changes (`.js` → `.cjs`/`.mjs`)
|
|
264
425
|
|
|
265
|
-
> **Comparison** — `tshy` was designed to enable dual-package builds powered by the `tsc` compiler. To make this work, it relies on a specific file structure and the creation of temporary `package.json` files to accommodate the various idiosyncrasies of Node.js module resolution.
|
|
426
|
+
> **Comparison** — `tshy` was designed to enable dual-package builds powered by the `tsc` compiler. To make this work, it relies on a specific file structure and the creation of temporary `package.json` files to accommodate the various idiosyncrasies of Node.js module resolution. It also requires the use of separate `dist/esm` and `dist/cjs` build subdirectories.
|
|
266
427
|
|
|
267
428
|
<br/>
|
|
268
429
|
|
|
269
430
|
### Can I use extension-less imports?
|
|
270
431
|
|
|
271
|
-
Yes! `zshy` supports whatever import style you prefer:
|
|
432
|
+
Yes! `zshy` supports whatever import style you prefer:
|
|
433
|
+
|
|
272
434
|
- `from "./utils"`: classic extensionless imports
|
|
273
435
|
- `from "./utils.js"`: ESM-friendly extensioned imports
|
|
274
436
|
- `from "./util.ts"`: recently supported natively via[`rewriteRelativeImportExtensions`](https://www.typescriptlang.org/tsconfig/#rewriteRelativeImportExtensions)
|
|
275
437
|
|
|
276
|
-
Use whatever you like; `zshy` will rewrite
|
|
438
|
+
Use whatever you like; `zshy` will rewrite all imports/exports properly during the build process.
|
|
277
439
|
|
|
278
440
|
> **Comparison** — `tshy` forces you to use `.js` imports throughout your codebase. While this is generally a good practice, it's not always feasible, and there are hundreds of thousands of existing TypeScript codebases reliant on extensionless imports.
|
|
279
441
|
|
|
280
442
|
<br/>
|
|
281
443
|
|
|
282
|
-
###
|
|
444
|
+
### What about `package.json#/exports`?
|
|
283
445
|
|
|
284
446
|
Your exports map is automatically written into your `package.json` when you run `zshy`. The generated exports map looks like this:
|
|
285
447
|
|
|
@@ -294,18 +456,18 @@ Your exports map is automatically written into your `package.json` when you run
|
|
|
294
456
|
},
|
|
295
457
|
+ "exports": { // auto-generated by zshy
|
|
296
458
|
+ ".": {
|
|
297
|
-
+ "types": "./
|
|
298
|
-
+ "import": "./
|
|
299
|
-
+ "require": "./
|
|
459
|
+
+ "types": "./dist/index.d.cts",
|
|
460
|
+
+ "import": "./dist/index.js",
|
|
461
|
+
+ "require": "./dist/index.cjs"
|
|
300
462
|
+ },
|
|
301
463
|
+ "./utils": {
|
|
302
|
-
+ "types": "./
|
|
303
|
-
+ "import": "./
|
|
304
|
-
+ "require": "./
|
|
464
|
+
+ "types": "./dist/utils.d.cts",
|
|
465
|
+
+ "import": "./dist/utils.js",
|
|
466
|
+
+ "require": "./dist/utils.cjs"
|
|
305
467
|
+ },
|
|
306
468
|
+ "./plugins/*": {
|
|
307
|
-
+ "import": "./
|
|
308
|
-
+ "require": "./
|
|
469
|
+
+ "import": "./dist/src/plugins/*",
|
|
470
|
+
+ "require": "./dist/src/plugins/*"
|
|
309
471
|
+ }
|
|
310
472
|
+ }
|
|
311
473
|
}
|
|
@@ -324,7 +486,7 @@ import mod from "pkg"; ^^^^^
|
|
|
324
486
|
// ^ The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("pkg")' call instead.
|
|
325
487
|
```
|
|
326
488
|
|
|
327
|
-
By having `"types"` point to the `.d.cts` declarations, this error will never happen. Technically, we're lying to TypeScript and telling it to always assume our code is CommonJS; in practice, this has no real consequences and maximizes compatibility. To learn more, read the ["Masquerading as ESM"](https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseESM.md) and ["Masquerading as CJS"](https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md) writeups from Are The Types Wrong.
|
|
489
|
+
By having `"types"` point to the `.d.cts` declarations, this error will never happen. Technically, we're lying to TypeScript and telling it to always assume our code is CommonJS; in practice, this has no real consequences and maximizes compatibility. To learn more, read the ["Masquerading as ESM"](https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseESM.md) and ["Masquerading as CJS"](https://github.com/arethetypeswrong/arethetypeswrong.github.io/blob/main/docs/problems/FalseCJS.md) writeups from Are The Types Wrong.
|
|
328
490
|
|
|
329
491
|
> **Comparison** — `tshy` generates independent (but identical) `.d.ts` files in `dist/esm` and `dist/cjs`. This can cause [Excessively Deep](https://github.com/colinhacks/zod/issues/4422) errors if users of the library use declaration merging (`declare module {}`) for plugins/extensions. [Zod](https://github.com/colinhacks/zod), [day.js](https://day.js.org/), and others rely on this pattern for plugins.
|
|
330
492
|
|
|
@@ -332,25 +494,33 @@ By having `"types"` point to the `.d.cts` declarations, this error will never ha
|
|
|
332
494
|
|
|
333
495
|
### Can it support React Native legacy or non-Node.js environments?
|
|
334
496
|
|
|
335
|
-
Yes! This is one of the key reasons `zshy` was originally developed
|
|
497
|
+
Yes! This is one of the key reasons `zshy` was originally developed. Many environments don't support `package.json#/exports` yet:
|
|
336
498
|
|
|
337
|
-
|
|
499
|
+
- Node.js v12.7 or earlier
|
|
500
|
+
- React Native - The Metro bundler does not support `"exports"` by default
|
|
501
|
+
- TypeScript projects with legacy configs — e.g. `"module": "commonjs"`
|
|
502
|
+
|
|
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_:
|
|
338
504
|
|
|
339
505
|
1. Remove `"type": "module"` from your `package.json` (if present)
|
|
340
506
|
2. Put your source files in your package root (not in a `src` directory)
|
|
341
507
|
3. Set `outDir: "."` in your `tsconfig.json`
|
|
508
|
+
4. Configure `"exclude"` in `package.json` to exclude all source files:
|
|
342
509
|
|
|
343
|
-
|
|
510
|
+
```jsonc
|
|
511
|
+
{
|
|
512
|
+
// ...
|
|
513
|
+
"exclude": ["**/*.ts", "**/*.tsx", "**/*.cts", "**/*.mts", "node_modules"]
|
|
514
|
+
}
|
|
515
|
+
```
|
|
344
516
|
|
|
345
|
-
|
|
346
|
-
2. **TypeScript projects using legacy configs** - e.g. `"module": "commonjs"`
|
|
347
|
-
3. **React Native** - The Metro bundler does not support `"exports"` by default
|
|
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.
|
|
348
518
|
|
|
349
|
-
<br/>
|
|
519
|
+
<br/>
|
|
350
520
|
|
|
351
521
|
### Is it fast?
|
|
352
522
|
|
|
353
|
-
Not really.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
523
|
+
Not really. It uses `tsc` to typecheck your codebase, which is a lot slower than using a bundler that strips types. That said:
|
|
524
|
+
|
|
525
|
+
1. You _should_ be type checking your code during builds
|
|
526
|
+
2. TypeScript is [about to get 10x faster](https://devblogs.microsoft.com/typescript/typescript-native-port/)
|