Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/plugins-node-subpath-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@xnetjs/plugins': patch
---

`@xnetjs/plugins/node` now reliably ships its type declarations. The two bundles
were built concurrently into overlapping output directories, so the main
bundle's clean step could delete `dist/services/node.d.ts` after the Node bundle
had written it — and the build still exited 0. A published package could
therefore carry `dist/services/node.js` with no declarations beside it, leaving
consumers to resolve the subpath as untyped JavaScript.
2 changes: 1 addition & 1 deletion packages/plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"provenance": true
},
"scripts": {
"build": "tsup",
"build": "tsup && tsup --config tsup.node.config.ts",
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit",
Expand Down
51 changes: 28 additions & 23 deletions packages/plugins/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import { defineConfig } from 'tsup'

export default defineConfig([
// Browser-compatible bundle (main entry)
{
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
outDir: 'dist',
splitting: false,
// Mark workspace packages as external - they're bundled by the consumer
external: ['@xnetjs/core', '@xnetjs/data']
},
// Node.js-only bundle (server-side code)
{
entry: ['src/services/node.ts'],
format: ['esm'],
dts: true,
outDir: 'dist/services',
splitting: false,
// Mark Node.js built-ins as external
external: ['http', 'child_process', 'net', 'readline', 'url', 'crypto', 'fs/promises', 'path']
}
])
// Browser-compatible bundle (main entry).
//
// The Node-only bundle lives in `tsup.node.config.ts` and is built as a
// SEPARATE, SEQUENTIAL tsup invocation (see the `build` script) rather than as a
// second element of an exported array. tsup runs array configs CONCURRENTLY,
// and this config's `clean` covers the whole of `dist/` — a strict superset of
// the Node bundle's `dist/services/` output. tsup cleans twice: `**/*` before
// the ESM phase, then `**/*.d.{ts,mts,cts}` RECURSIVELY before the DTS phase.
// Whichever of those landed after the Node bundle had written a file silently
// deleted it, and the build still exited 0 — so a green build could ship
// `dist/services/node.js` with no `node.d.ts` beside it. Consumers then
// resolved `@xnetjs/plugins/node` to bare JS and degraded it to `any`
// (TS7016), which surfaced downstream as a pile of unrelated-looking TS7006
// "implicitly has an 'any' type" errors on every callback parameter in
// `@xnetjs/cli`. Turbo cached the truncated dist as a success on top of that.
//
// Keep these two builds in separate files and sequential: the clean and the
// write must never be able to interleave.
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
outDir: 'dist',
splitting: false,
// Mark workspace packages as external - they're bundled by the consumer
external: ['@xnetjs/core', '@xnetjs/data']
})
18 changes: 18 additions & 0 deletions packages/plugins/tsup.node.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { defineConfig } from 'tsup'

// Node.js-only bundle (server-side code), published as `@xnetjs/plugins/node`.
//
// Built by its own tsup invocation AFTER `tsup.config.ts`, never alongside it —
// see the comment there for why concurrency here silently truncated the output.
// `clean` is scoped to this outDir, so it can only ever remove what this config
// produces.
export default defineConfig({
entry: ['src/services/node.ts'],
format: ['esm'],
dts: true,
clean: true,
outDir: 'dist/services',
splitting: false,
// Mark Node.js built-ins as external
external: ['http', 'child_process', 'net', 'readline', 'url', 'crypto', 'fs/promises', 'path']
})
Loading