@d1g1tal/tsbuild 1.3.2 → 1.5.0

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
@@ -8,7 +8,7 @@
8
8
  [![Node.js](https://img.shields.io/node/v/@d1g1tal/tsbuild)](https://nodejs.org)
9
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
10
10
 
11
- A TypeScript build tool that combines three tools into one workflow: **TypeScript's type system** for correctness, **esbuild** for speed, and **SWC** for legacy decorator metadata (optional, not installed by default). Built for modern ESM-only projects on Node.js 20.16.0+.
11
+ A TypeScript build tool that combines three tools into one workflow: **TypeScript's type system** for correctness, **esbuild** for speed, and **SWC** for legacy decorator metadata (optional, not installed by default). Built for modern ESM-only projects on Node.js 22+.
12
12
 
13
13
  TC39 standard decorators are supported natively — no additional dependencies needed. SWC is only required if you are still using `experimentalDecorators` with `emitDecoratorMetadata`.
14
14
 
@@ -42,38 +42,6 @@ The build runs in two phases:
42
42
 
43
43
  If `declaration` is not enabled, phase 2 is just the esbuild step.
44
44
 
45
- ## Quick Start
46
-
47
- The only thing tsbuild requires in `tsconfig.json` is an `outDir`. Everything else carries over from your existing config:
48
-
49
- ```jsonc
50
- {
51
- "compilerOptions": {
52
- "outDir": "./dist"
53
- // ... your existing TypeScript config
54
- },
55
- "tsbuild": {} // entry points are inferred from package.json automatically
56
- }
57
- ```
58
-
59
- Then, if tsbuild is installed globally:
60
-
61
- ```bash
62
- tsbuild
63
- ```
64
-
65
- Or if installed locally as a dev dependency, add a script to `package.json` and run it:
66
-
67
- ```json
68
- { "scripts": { "build": "tsbuild" } }
69
- ```
70
-
71
- ```bash
72
- pnpm build
73
- ```
74
-
75
- That's it. tsbuild reads your `compilerOptions`, infers entry points from your `package.json`, and builds. See [Configuration Options](#configuration-options) for everything you can customise.
76
-
77
45
  ## Installation
78
46
 
79
47
  ### Global Installation (Recommended for CLI usage)
@@ -111,8 +79,109 @@ yarn add -D @d1g1tal/tsbuild
111
79
 
112
80
  ### Requirements
113
81
 
114
- - **Node.js**: >=20.16.0
115
- - **pnpm**: >=9.0.0
82
+ - **Node.js**: >=22.0.0
83
+ - **pnpm**: >=10.13.0 (if using corepack)
84
+
85
+ ## Quick Start
86
+
87
+ The only thing tsbuild requires in `tsconfig.json` is an `outDir`. Everything else carries over from your existing config.
88
+
89
+ ### Minimal config — no `tsbuild` section needed
90
+
91
+ ```jsonc
92
+ {
93
+ "compilerOptions": {
94
+ "outDir": "./dist"
95
+ // ... your existing TypeScript config
96
+ }
97
+ }
98
+ ```
99
+
100
+ Entry points are inferred from `package.json` automatically, and all dependencies are treated as external by default.
101
+
102
+ ### Bundle a specific package into the output
103
+
104
+ By default, bare specifiers (e.g. `lodash-es`) are kept as external imports. Use `noExternal` to force a package to be inlined into the bundle:
105
+
106
+ ```jsonc
107
+ {
108
+ "compilerOptions": {
109
+ "outDir": "./dist"
110
+ // ... your existing TypeScript config
111
+ },
112
+ "tsbuild": {
113
+ "noExternal": ["evicting-cache"] // bundle evicting-cache into the output instead of leaving it as an import
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### Preferred `tsconfig.json` setup — incremental (recommended)
119
+
120
+ `incremental` defaults to `true` in tsbuild unless you explicitly set it to `false` in your `tsconfig.json`. With incremental enabled, TypeScript only re-emits changed files on each build and the declaration cache is preserved across runs, making repeated builds significantly faster.
121
+
122
+ ```jsonc
123
+ {
124
+ "compilerOptions": {
125
+ "outDir": "./dist",
126
+ "declaration": true,
127
+ "incremental": true, // redundant — tsbuild enables this by default, but explicit is clear
128
+ "isolatedDeclarations": true, // recommended: enables faster parallel declaration emit
129
+ "isolatedModules": true,
130
+ "verbatimModuleSyntax": true,
131
+ "strict": true,
132
+ "target": "ESNext",
133
+ "module": "ESNext",
134
+ "moduleResolution": "Bundler", // recommended for library builds processed by a bundler
135
+ // lib controls platform detection — omitting "DOM" targets Node.js (platform: "node").
136
+ // Add "DOM" to target the browser (platform: "browser").
137
+ "lib": ["ESNext"] // Node.js library — no DOM APIs
138
+ // "lib": ["ESNext", "DOM"] // Browser library — includes DOM APIs, sets platform to "browser"
139
+ }
140
+ }
141
+ ```
142
+
143
+ ### Preferred `tsconfig.json` setup — non-incremental
144
+
145
+ Set `incremental: false` to opt out of the `.tsbuildinfo` cache entirely. Every build is a full compilation from scratch. Useful for CI environments where you want deterministic, cache-free output.
146
+
147
+ ```jsonc
148
+ {
149
+ "compilerOptions": {
150
+ "outDir": "./dist",
151
+ "declaration": true,
152
+ "incremental": false, // disables TypeScript's .tsbuildinfo cache and tsbuild's DTS cache
153
+ "isolatedDeclarations": true,
154
+ "isolatedModules": true,
155
+ "verbatimModuleSyntax": true,
156
+ "strict": true,
157
+ "target": "ESNext",
158
+ "module": "ESNext",
159
+ "moduleResolution": "Bundler", // recommended for library builds processed by a bundler
160
+ // lib controls platform detection — omitting "DOM" targets Node.js (platform: "node").
161
+ // Add "DOM" to target the browser (platform: "browser").
162
+ "lib": ["ESNext"] // Node.js library — no DOM APIs
163
+ // "lib": ["ESNext", "DOM"] // Browser library — includes DOM APIs, sets platform to "browser"
164
+ }
165
+ }
166
+ ```
167
+
168
+ Then, if tsbuild is installed globally:
169
+
170
+ ```bash
171
+ tsbuild
172
+ ```
173
+
174
+ Or if installed locally as a dev dependency, add a script to `package.json` and run it:
175
+
176
+ ```json
177
+ { "scripts": { "build": "tsbuild" } }
178
+ ```
179
+
180
+ ```bash
181
+ pnpm build
182
+ ```
183
+
184
+ That's it. tsbuild reads your `compilerOptions`, infers entry points from your `package.json`, and builds. See [Configuration Options](#configuration-options) for everything you can customize.
116
185
 
117
186
  ## Usage
118
187
 
@@ -122,7 +191,7 @@ yarn add -D @d1g1tal/tsbuild
122
191
 
123
192
  Because tsbuild uses the TypeScript compiler API directly, it reads your `compilerOptions` automatically. There is no need to re-declare `target`, `module`, `lib`, `strict`, `paths`, `moduleResolution`, `baseUrl`, or any other TypeScript settings in a separate config — they are already in your `tsconfig.json`, and tsbuild honours them as-is.
124
193
 
125
- The `tsbuild` section only covers options that don't belong in `compilerOptions`: bundling behaviour, entry points, watch mode, output formatting, and similar build-specific settings.
194
+ The `tsbuild` section only covers options that don't belong in `compilerOptions`: bundling behavior, entry points, watch mode, output formatting, and similar build-specific settings.
126
195
 
127
196
  This means your type-checker and your build always use the exact same TypeScript configuration — no drift, no duplication.
128
197
 
@@ -133,7 +202,7 @@ Declaration generation is **not required**. If `declaration: true` is already se
133
202
 
134
203
  Everything else carries over automatically.
135
204
 
136
- Add a `tsbuild` property to your `tsconfig.json` with only the options you need to customise:
205
+ Add a `tsbuild` property to your `tsconfig.json` with only the options you need to customize:
137
206
 
138
207
  ```jsonc
139
208
  {
@@ -215,17 +284,17 @@ tsbuild uses two separate caches to speed up repeated builds, and two flags to c
215
284
 
216
285
  ### How it works
217
286
 
218
- Enable incremental compilation in `tsconfig.json`:
287
+ Incremental compilation is **enabled by default** — no configuration needed. To opt out, explicitly set `incremental: false` in `tsconfig.json`:
219
288
 
220
289
  ```jsonc
221
290
  {
222
291
  "compilerOptions": {
223
- "incremental": true
292
+ "incremental": false // disables TypeScript's .tsbuildinfo cache and tsbuild's DTS cache
224
293
  }
225
294
  }
226
295
  ```
227
296
 
228
- With this set, each build maintains two caches inside a `.tsbuild/` directory:
297
+ With incremental enabled, each build maintains two caches inside a `.tsbuild/` directory:
229
298
 
230
299
  | Cache | File | What it stores |
231
300
  |-------|------|----------------|
@@ -234,6 +303,20 @@ With this set, each build maintains two caches inside a `.tsbuild/` directory:
234
303
 
235
304
  On each build, TypeScript reads `.tsbuildinfo` to determine what changed and only re-emits those files. Changed `.d.ts` files overwrite their entries in the DTS cache; unchanged entries remain valid. If nothing changed, TypeScript skips emission entirely and the output phase is skipped too — this is why incremental rebuilds with no changes take ~5ms.
236
305
 
306
+ ### Ignoring the cache directory
307
+
308
+ The `.tsbuild/` directory contains build artifacts that should not be committed to source control. Add it to your `.gitignore`:
309
+
310
+ ```bash
311
+ echo '.tsbuild/' >> .gitignore
312
+ ```
313
+
314
+ Or add the entry manually:
315
+
316
+ ```gitignore
317
+ .tsbuild/
318
+ ```
319
+
237
320
  ### Flags
238
321
 
239
322
  **`--force` (`-f`)** — Runs the output phase (esbuild + DTS bundling) even when TypeScript detects no changes. Useful when something outside the source files changed (e.g. an environment variable or esbuild config) and you need to regenerate output without touching the caches.
@@ -441,7 +524,7 @@ When a circular dependency is detected between declaration files, tsbuild emits
441
524
 
442
525
  tsbuild is designed for speed:
443
526
 
444
- - **Incremental builds** - Only recompiles changed files
527
+ - **Incremental builds** - Only recompile changed files
445
528
  - **In-memory declarations** - No intermediate disk I/O for `.d.ts` files
446
529
  - **Parallel processing** - Declaration bundling and transpilation run in parallel after type checking completes
447
530
  - **Smart caching** - Leverages `.tsbuildinfo` for TypeScript incremental compilation
@@ -29,7 +29,7 @@ import {
29
29
  toEsTarget,
30
30
  toJsxRenderingMode,
31
31
  typeMatcher
32
- } from "./7FPDHUPW.js";
32
+ } from "./UYXU5EAU.js";
33
33
 
34
34
  // src/errors.ts
35
35
  import { SyntaxKind } from "typescript";
@@ -1933,6 +1933,13 @@ var IncrementalBuildCache = class {
1933
1933
  isBuildInfoFile(filePath) {
1934
1934
  return filePath === this.buildInfoPath;
1935
1935
  }
1936
+ /**
1937
+ * Checks if the cache is valid (not invalidated).
1938
+ * @returns True if the cache is valid, false if it has been invalidated
1939
+ */
1940
+ isValid() {
1941
+ return !this.invalidated;
1942
+ }
1936
1943
  /**
1937
1944
  * Custom inspection tag for type.
1938
1945
  * @returns The string 'IncrementalBuildCache'
@@ -2091,7 +2098,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2091
2098
  return Files.empty(this.buildConfiguration.outDir);
2092
2099
  }
2093
2100
  async build() {
2094
- Logger.header(`\u{1F680} tsbuild v${"1.3.2"}${this.configuration.compilerOptions.incremental ? " [incremental]" : ""}`);
2101
+ Logger.header(`\u{1F680} tsbuild v${"1.5.0"}${this.configuration.compilerOptions.incremental && this.configuration.buildCache?.isValid() ? " [incremental]" : ""}`);
2095
2102
  try {
2096
2103
  const processes = [];
2097
2104
  const filesWereEmitted = await this.typeCheck();
@@ -2150,7 +2157,7 @@ var _TypeScriptProject = class _TypeScriptProject {
2150
2157
  }
2151
2158
  if (this.configuration.compilerOptions.emitDecoratorMetadata) {
2152
2159
  try {
2153
- const { swcDecoratorMetadataPlugin } = await import("./LEZQQWX3.js");
2160
+ const { swcDecoratorMetadataPlugin } = await import("./RBRXNRTQ.js");
2154
2161
  plugins.push(swcDecoratorMetadataPlugin);
2155
2162
  } catch {
2156
2163
  throw new ConfigurationError("emitDecoratorMetadata is enabled but @swc/core is not installed. Install it with: pnpm add -D @swc/core");
@@ -2357,7 +2364,9 @@ var _TypeScriptProject = class _TypeScriptProject {
2357
2364
  compilerOptions: {
2358
2365
  ...{ outDir: defaultOutDirectory, noEmit: false, sourceMap: false, incremental: true, tsBuildInfoFile: Paths.join(cacheDirectory, buildInfoFile), lib: [] },
2359
2366
  ...configResult.config.compilerOptions,
2360
- ...typeScriptOptions.compilerOptions
2367
+ ...typeScriptOptions.compilerOptions,
2368
+ // Always include 'node' and merge with any user-specified types
2369
+ types: [.../* @__PURE__ */ new Set(["node", ...configResult.config.compilerOptions?.types ?? [], ...typeScriptOptions.compilerOptions?.types ?? []])]
2361
2370
  }
2362
2371
  };
2363
2372
  const { options, fileNames, errors } = parseJsonConfigFileContent(baseConfig, sys2, directory);
@@ -3,7 +3,7 @@ import {
3
3
  Json,
4
4
  Paths,
5
5
  typeScriptExtensionExpression
6
- } from "./7FPDHUPW.js";
6
+ } from "./UYXU5EAU.js";
7
7
 
8
8
  // src/plugins/decorator-metadata.ts
9
9
  import { dirname } from "node:path";
@@ -61,6 +61,8 @@ var compilerOptionOverrides = {
61
61
  checkJs: false,
62
62
  // Skip declaration map generation. TODO - Would love to figure out how to combine them into a single file / entry point
63
63
  declarationMap: false,
64
+ // Force .d.ts output to outDir so the bundler can reliably find declaration files
65
+ declarationDir: void 0,
64
66
  // Skip type-checking all dependencies
65
67
  skipLibCheck: true,
66
68
  // Ensure TS2742 errors are visible when `true`. TODO - Figure out how to have this work with a value of `true`
package/dist/index.d.ts CHANGED
@@ -188,9 +188,15 @@ type CachedDeclaration = {
188
188
  };
189
189
  /** Interface for build cache operations */
190
190
  interface BuildCache {
191
+ /** Invalidates the build cache */
191
192
  invalidate(): void;
193
+ /** Restores cached declaration files into the provided map */
192
194
  restore(target: Map<string, CachedDeclaration>): Promise<void>;
195
+ /** Saves declaration files to the cache */
193
196
  save(source: ReadonlyMap<string, CachedDeclaration>): Promise<void>;
197
+ /** Checks if the cache is valid */
198
+ isValid(): boolean;
199
+ /** Checks if a file path is the TypeScript build info file */
194
200
  isBuildInfoFile(filePath: AbsolutePath): boolean;
195
201
  }
196
202
  type TypeScriptConfiguration = Readonly<PrettyModify<TypeScriptOptions, {
@@ -236,6 +242,7 @@ type CompilerOptionOverrides = Readonly<{
236
242
  allowJs: false;
237
243
  checkJs: false;
238
244
  declarationMap: false;
245
+ declarationDir: undefined;
239
246
  skipLibCheck: true;
240
247
  preserveSymlinks: false;
241
248
  target: ScriptTarget.ESNext;
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  TypeScriptProject
3
- } from "./QG4L36TP.js";
4
- import "./7FPDHUPW.js";
3
+ } from "./4BKT57QY.js";
4
+ import "./UYXU5EAU.js";
5
5
  export {
6
6
  TypeScriptProject
7
7
  };
package/dist/tsbuild.js CHANGED
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  BuildError,
4
4
  TypeScriptProject
5
- } from "./QG4L36TP.js";
6
- import "./7FPDHUPW.js";
5
+ } from "./4BKT57QY.js";
6
+ import "./UYXU5EAU.js";
7
7
 
8
8
  // src/tsbuild.ts
9
9
  import { sys } from "typescript";
@@ -30,7 +30,7 @@ if (help) {
30
30
  process.exit(0);
31
31
  }
32
32
  if (version) {
33
- console.log("1.3.2");
33
+ console.log("1.5.0");
34
34
  process.exit(0);
35
35
  }
36
36
  var typeScriptOptions = {
package/package.json CHANGED
@@ -1,8 +1,30 @@
1
1
  {
2
2
  "name": "@d1g1tal/tsbuild",
3
- "version": "1.3.2",
4
- "packageManager": "pnpm@10.30.3",
3
+ "author": "D1g1talEntr0py",
4
+ "version": "1.5.0",
5
+ "license": "MIT",
5
6
  "description": "A fast, ESM-only TypeScript build tool combining the TypeScript API for type checking and declaration generation, esbuild for bundling, and SWC for decorator metadata.",
7
+ "homepage": "https://github.com/D1g1talEntr0py/tsbuild#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/D1g1talEntr0py/tsbuild.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/D1g1talEntr0py/tsbuild/issues"
14
+ },
15
+ "maintainers": [
16
+ {
17
+ "name": "D1g1talEntr0py",
18
+ "email": "jason.dimeo@gmail.com"
19
+ }
20
+ ],
21
+ "engines": {
22
+ "node": ">=22.0.0"
23
+ },
24
+ "publishConfig": {
25
+ "registry": "https://registry.npmjs.org",
26
+ "access": "public"
27
+ },
6
28
  "type": "module",
7
29
  "exports": {
8
30
  ".": {
@@ -12,47 +34,13 @@
12
34
  },
13
35
  "files": [
14
36
  "./dist",
15
- "./schema.json"
37
+ "./schema.json",
38
+ "README.md",
39
+ "LICENSE"
16
40
  ],
17
41
  "bin": {
18
42
  "tsbuild": "./dist/tsbuild.js"
19
43
  },
20
- "scripts": {
21
- "prepare": "git config core.hooksPath .githooks",
22
- "build": "tsx ./src/tsbuild.ts",
23
- "build:watch": "tsx ./src/tsbuild.ts --watch",
24
- "type-check": "tsx ./src/tsbuild.ts --noEmit",
25
- "lint": "eslint ./src",
26
- "test": "vitest run",
27
- "test:coverage": "vitest run --coverage",
28
- "prepublishOnly": "pnpm lint && pnpm build"
29
- },
30
- "keywords": [
31
- "typescript",
32
- "build",
33
- "bundler",
34
- "esbuild",
35
- "declarations",
36
- "dts",
37
- "esm"
38
- ],
39
- "author": "D1g1talEntr0py",
40
- "license": "MIT",
41
- "engines": {
42
- "node": ">=20.16.0"
43
- },
44
- "repository": {
45
- "type": "git",
46
- "url": "git+https://github.com/D1g1talEntr0py/tsbuild.git"
47
- },
48
- "publishConfig": {
49
- "registry": "https://registry.npmjs.org",
50
- "access": "public"
51
- },
52
- "bugs": {
53
- "url": "https://github.com/D1g1talEntr0py/tsbuild/issues"
54
- },
55
- "homepage": "https://github.com/D1g1talEntr0py/tsbuild#readme",
56
44
  "dependencies": {
57
45
  "@d1g1tal/watchr": "1.0.0",
58
46
  "esbuild": "^0.27.3",
@@ -60,17 +48,34 @@
60
48
  },
61
49
  "devDependencies": {
62
50
  "@eslint/js": "^10.0.1",
63
- "@types/node": "^25.3.0",
51
+ "@types/node": "^25.3.5",
64
52
  "@typescript-eslint/eslint-plugin": "^8.56.1",
65
53
  "@typescript-eslint/parser": "^8.56.1",
66
54
  "@vitest/coverage-v8": "4.0.18",
67
- "eslint": "^10.0.2",
55
+ "eslint": "^10.0.3",
68
56
  "eslint-plugin-jsdoc": "^62.7.1",
69
57
  "fs-monkey": "^1.1.0",
70
- "memfs": "^4.56.10",
58
+ "memfs": "^4.56.11",
71
59
  "tsx": "^4.21.0",
72
60
  "typescript": "5.9.3",
73
61
  "typescript-eslint": "^8.56.1",
74
62
  "vitest": "^4.0.18"
63
+ },
64
+ "keywords": [
65
+ "typescript",
66
+ "build",
67
+ "bundler",
68
+ "esbuild",
69
+ "declarations",
70
+ "dts",
71
+ "esm"
72
+ ],
73
+ "scripts": {
74
+ "build": "tsx ./src/tsbuild.ts",
75
+ "build:watch": "tsx ./src/tsbuild.ts --watch",
76
+ "type-check": "tsx ./src/tsbuild.ts --noEmit",
77
+ "lint": "eslint ./src",
78
+ "test": "vitest run",
79
+ "test:coverage": "vitest run --coverage"
75
80
  }
76
- }
81
+ }