@temir.ra/create-ts-lib 0.7.5 → 0.8.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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Version 0
2
2
 
3
+ ## 0.8.0
4
+
5
+ 1. Updated wording in the Publish section of the generated README.
6
+ 2. `build:tsc` step is now generated per default.
7
+ 3. Added `./constants` entrypoint to `package.json`.
8
+
9
+ ## 0.7.6
10
+
11
+ 1. Updated `typescript` to `6.0.3`.
12
+ 2. Cleaned up minor `README.md` inconsistencies.
13
+ 3. Aligned wording with [`RFC 2119`](https://datatracker.ietf.org/doc/html/rfc2119).
14
+ 4. Updated files from `template` template.
15
+
3
16
  ## 0.7.5
4
17
 
5
18
  1. Updated files from `@temir.ra/template@0.1.6` template.
package/README.md CHANGED
@@ -7,14 +7,10 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
7
7
  1. [Quick Start](#quick-start)
8
8
  2. [Documentation](#documentation)
9
9
  1. [`package.json`](#packagejson)
10
- 2. [`"bin"` field in `package.json`](#bin-field-in-packagejson)
11
- 3. [`tsconfig.json`](#tsconfigjson)
12
- 4. [TSC Compilation](#tsc-compilation)
13
- 1. [`tsconfig.build.json`](#tsconfigbuildjson)
14
- 2. [`package.json`](#packagejson-1)
15
- 5. [Script `scripts/build-bundle.ts`](#script-scriptsbuild-bundlets)
10
+ 2. [Script `scripts/build-bundle.ts`](#script-scriptsbuild-bundlets)
16
11
  1. [CDN Map `scripts/cdn-rewrite-map.json`](#cdn-map-scriptscdn-rewrite-mapjson)
17
- 6. [Asset Resolution](#asset-resolution)
12
+ 3. [`tsconfig.build.json`](#tsconfigbuildjson)
13
+ 4. [Asset Resolution](#asset-resolution)
18
14
  1. [Externalized - loaded from CDN or `node_modules/`](#externalized---loaded-from-cdn-or-node_modules)
19
15
  2. [Bundled - absorbed into the consumer's output](#bundled---absorbed-into-the-consumers-output)
20
16
  3. [Contract](#contract)
@@ -22,6 +18,7 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
22
18
  2. [Accessing assets](#accessing-assets)
23
19
  3. [README statement for library consumers](#readme-statement-for-library-consumers)
24
20
  4. [When the library is bundled by the consumer](#when-the-library-is-bundled-by-the-consumer)
21
+ 5. [`"bin"` field in `package.json`](#bin-field-in-packagejson)
25
22
  3. [DevOps](#devops)
26
23
  1. [Change Management](#change-management)
27
24
  2. [Publish](#publish)
@@ -85,6 +82,7 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
85
82
  "type": "module",
86
83
 
87
84
  // package entry points
85
+ // multiple entry points can be configured (".", "./module/", etc.)
88
86
  //
89
87
  // scripts/build-bundle.ts (non-standard) export condition:
90
88
  // "entrypoint" - locates the source entry point for bundling
@@ -92,13 +90,13 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
92
90
  // standard export conditions:
93
91
  // "types" - TypeScript consumers; resolves to the declaration files;
94
92
  // "browser" - browser bundler consumers; resolves to the bundled output
95
- // "import" - ESM consumers; resolves to the compiled module output
93
+ // "import" - ESM consumers; resolves to the bundled/compiled output
96
94
  "exports": {
97
95
  ".": {
98
96
  "entrypoint": "./src/index.ts",
99
97
  "types": "./dist/index.d.ts",
100
98
  "browser": "./dist/index.bundle.js",
101
- "import": "./dist/index.js"
99
+ "import": "./dist/index.bundle.js"
102
100
  }
103
101
  },
104
102
 
@@ -143,14 +141,14 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
143
141
  "prebuild": "bun run buildinfo",
144
142
 
145
143
  // convenience script to run the build steps in sequence
146
- "build": "bun run build:tsc && bun run build:bundle && bun run build:cli-bundle",
147
-
148
- // compiles the library to declaration files and ESM JavaScript in dist/
149
- "build:tsc": "tsc --project tsconfig.build.json",
144
+ "build": "bun run build:bundle && bun run build:tsc && bun run build:cli-bundle",
150
145
 
151
146
  // bundles the library into ESM and IIFE formats for distribution
152
147
  "build:bundle": "bun run scripts/build-bundle.ts",
153
148
 
149
+ // compiles the library to declaration files and ESM JavaScript in dist/
150
+ "build:tsc": "tsc --project tsconfig.build.json",
151
+
154
152
  // bundles the CLI into a single file for distribution; requires the "bin" field to be set to the bundled output
155
153
  "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
156
154
 
@@ -161,89 +159,29 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
161
159
 
162
160
  It is highly recommended to include `tests/` in the `files` field. Note, that `tests/` is not included by default in the generated `package.json`.
163
161
 
164
- ## `"bin"` field in `package.json`
165
-
166
- For CLI packages, add the following to `package.json`:
167
-
168
- ```json
169
- {
170
- // ... ,
171
- "bin": "./dist/cli.bundle.js",
172
- "scripts": {
173
- // ... ,
174
- "build": "... && bun run build:cli-bundle",
175
- // ... ,
176
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
177
- }
178
- }
179
- ```
180
-
181
- `src/cli.ts` must begin with a hashbang so the OS knows which interpreter to invoke when the binary is executed directly. Bun preserves it in the bundled output.
182
-
183
- ```typescript
184
- #!/usr/bin/env node
185
- ```
162
+ ## Script `scripts/build-bundle.ts`
186
163
 
187
- If the package exports a CLI only and is not intended to be imported in other packages, the `exports` field can be omitted.
164
+ Bundles the library to ESM and IIFE formats. Entry points are resolved from the `entrypoint` condition in the `exports` field of `package.json`. Note, the `entrypoint` condition is a custom, non-standard export condition used solely for build tooling.
188
165
 
189
- ## `tsconfig.json`
166
+ Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
190
167
 
191
- Selected fields are documented in the [`create-workspace` README](https://www.npmjs.com/package/@temir.ra/create-workspace#tsconfigjson).
168
+ ### CDN Map `scripts/cdn-rewrite-map.json`
192
169
 
193
- See the TypeScript documentation on [tsconfig.json](https://www.typescriptlang.org/tsconfig) for detailed explanations of all options.
170
+ Maps import specifiers to CDN URLs. During bundling, matching specifiers in source files are rewritten to their CDN equivalents.
194
171
 
195
- The following lists the additions and overrides relative to [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace#tsconfigjson).
172
+ `<VERSION>` in a URL is replaced with the version of the matching package from `package.json`.
196
173
 
197
174
  ```json
198
175
  {
199
-
200
- "compilerOptions": {
201
-
202
- // ... ,
203
-
204
- // emit .d.ts declaration files
205
- "declaration": true,
206
-
207
- // emit .d.ts.map files mapping declarations back to source
208
- "declarationMap": true,
209
-
210
- // emit only .d.ts files, no JavaScript; overridden in tsconfig.build.json
211
- "emitDeclarationOnly": true,
212
-
213
- // output directory for emitted files
214
- "outDir": "./dist"
215
-
216
- },
217
-
218
- "include": [
219
- // ... ,
220
- // include `scripts/**/*.json` for script configuration files
221
- "scripts/**/*.json",
222
- // include `src/**/*.ts` for source files
223
- "src/**/*.ts"
224
- ],
225
- "exclude": [
226
- // ... ,
227
- // exclude `dist/`
228
- "dist"
229
- ]
230
-
176
+ "import-specifier": "https://cdn.jsdelivr.net/npm/package-name@<VERSION>/dist/index.bundle.js"
231
177
  }
232
178
  ```
233
179
 
234
- `declarationMap: true` enables go-to-definition for npm/bun consumers. For this to work, the original `.ts` source files must be accessible to the consumer. Consider adding `src/` to the `files` field in `package.json`.
235
-
236
- ## TSC Compilation
237
-
238
- Not generated by default. Enables file-for-file tsc compilation of `src/` to ESM JavaScript and declaration files alongside bundling.
239
-
240
- ### `tsconfig.build.json`
180
+ ## `tsconfig.build.json`
241
181
 
242
- Extends `tsconfig.json`, narrowing scope to `src/` only and switching to `nodenext` module resolution for strict ESM compliance.
182
+ `tsconfig.json` provided by [`workspace` template](https://www.npmjs.com/package/@temir.ra/create-workspace) is intended for development only. `tsconfig.build.json` extends it with settings for compiling the source files for distribution.
243
183
 
244
- Enables JavaScript output alongside declaration files for distribution.
245
-
246
- Development files (`dev.ts`, `tests/`, `scripts/`) are excluded.
184
+ See [`create-workspace` README](https://www.npmjs.com/package/@temir.ra/create-workspace#tsconfigjson) and [tsconfig.json](https://www.typescriptlang.org/tsconfig) for detailed explanations of all options.
247
185
 
248
186
  ```json
249
187
  {
@@ -253,14 +191,23 @@ Development files (`dev.ts`, `tests/`, `scripts/`) are excluded.
253
191
  "compilerOptions": {
254
192
 
255
193
  // narrows root to src/ for distribution output
256
- "rootDir": "./src",
194
+ "rootDir": "./src/",
257
195
 
258
196
  // nodenext enforces strict ESM compliance; imports must use explicit .js file extensions
259
197
  "module": "nodenext",
260
198
  "moduleResolution": "nodenext",
261
199
 
262
- // emit both JavaScript files and declaration files for distribution
263
- "emitDeclarationOnly": false,
200
+ // emit .d.ts declaration files
201
+ "declaration": true,
202
+
203
+ // emit .d.ts.map files mapping declarations back to source
204
+ "declarationMap": true,
205
+
206
+ // emit only .d.ts files, no JavaScript
207
+ "emitDeclarationOnly": true,
208
+
209
+ // output directory for emitted files
210
+ "outDir": "./dist/"
264
211
 
265
212
  },
266
213
 
@@ -270,10 +217,10 @@ Development files (`dev.ts`, `tests/`, `scripts/`) are excluded.
270
217
  ],
271
218
  // exclude development files and directories from distribution
272
219
  "exclude": [
273
- "node_modules",
274
- "dist",
275
- "tests",
276
- "scripts"
220
+ "node_modules/",
221
+ "dist/",
222
+ "tests/",
223
+ "scripts/"
277
224
  ]
278
225
 
279
226
  }
@@ -286,27 +233,40 @@ Development files (`dev.ts`, `tests/`, `scripts/`) are excluded.
286
233
  // ... ,
287
234
  "scripts": {
288
235
  // ... ,
289
- "build": "bun run build:tsc && bun run build:bundle",
236
+ "build": "... && bun run build:tsc",
290
237
  "build:tsc": "tsc --project tsconfig.build.json"
291
238
  }
292
239
  }
293
240
  ```
294
241
 
295
- ## Script `scripts/build-bundle.ts`
296
-
297
- Bundles the library to ESM and IIFE formats. Entry points are resolved from the `entrypoint` condition in the `exports` field of `package.json`. Note, the `entrypoint` condition is a custom, non-standard export condition used solely for build tooling.
298
-
299
- Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
242
+ Exports condition `import` may point to the compiled output instead of the bundled output `./dist/index.bundle.js` if `"emitDeclarationOnly": false`:
300
243
 
301
- ### CDN Map `scripts/cdn-rewrite-map.json`
302
-
303
- Maps import specifiers to CDN URLs. During bundling, matching specifiers in source files are rewritten to their CDN equivalents.
244
+ ```json
245
+ {
246
+ // ... ,
247
+ "exports": {
248
+ ".": {
249
+ // ... ,
250
+ "import": "./dist/index.js"
251
+ }
252
+ },
253
+ // ... ,
254
+ }
255
+ ```
304
256
 
305
- `<VERSION>` in a URL is replaced with the version of the matching package from `package.json`.
257
+ When `"declaration": true`, then exports condition `types` can be added to point to the declaration files:
306
258
 
307
259
  ```json
308
260
  {
309
- "import-specifier": "https://cdn.jsdelivr.net/npm/package-name@<VERSION>/dist/index.bundle.js"
261
+ // ... ,
262
+ "exports": {
263
+ ".": {
264
+ // ... ,
265
+ "types": "./dist/index.d.ts",
266
+ // ... ,
267
+ }
268
+ },
269
+ // ... ,
310
270
  }
311
271
  ```
312
272
 
@@ -335,7 +295,7 @@ https://your-own-cdn.com/<LIB_NAME>/index.js
335
295
 
336
296
  ### Bundled - absorbed into the consumer's output
337
297
 
338
- The consumer's bundler absorbs the library into their own output. Module identity is destroyed - `import.meta.url` now points to the consumer's bundle, not the library's. However, **the path relationship can be preserved by convention**: if the consumer copies the library's assets into their build output at the same relative path the library expects, `import.meta.url` resolution continues to work correctly.
298
+ The consumer's bundler absorbs the library into their own output. Module identity is destroyed - `import.meta.url` now points to the consumer's bundle, not the library's. However, **the path relationship can be preserved by convention**: if the consumer copies the library's assets into their output directory at the same relative path the library expects, `import.meta.url` resolution continues to work correctly.
339
299
 
340
300
  ### Contract
341
301
 
@@ -352,7 +312,7 @@ If the library has runtime assets, the following contract applies:
352
312
  1. **Copy the assets** - see [When the library is bundled by the consumer](#when-the-library-is-bundled-by-the-consumer) below.
353
313
  2. **Ensure the assets are served**
354
314
  - if the consumer is a web server, ensure the copied assets are served as static files
355
- - if the consumer is a bundler, ensure the copied assets are included in the bundle output
315
+ - if the consumer is a bundler, ensure the copied assets are included in the output directory
356
316
 
357
317
  #### Scoped assets directory convention
358
318
 
@@ -365,34 +325,55 @@ assets/
365
325
  └── ...
366
326
  ```
367
327
 
368
- This also prevents naming collisions when multiple libraries are bundled into the same consumer app. Each library's assets live under their own namespace; no library can shadow another's files.
369
-
370
328
  Add `assets/` to the `files` field in `package.json` so that the assets are included in the published package:
371
329
 
372
330
  ```json
331
+ {
332
+ // ... ,
373
333
  "files": [
374
- "dist",
375
- "CHANGELOG.md",
376
- "buildinfo.txt",
377
- "assets"
334
+ // ... ,
335
+ "assets/"
378
336
  ],
337
+ // ... ,
338
+ }
379
339
  ```
380
340
 
381
341
  #### Accessing assets
382
342
 
383
- Construct asset URLs directly from `import.meta.url`.
343
+ Construct asset URLs directly from `import.meta.url`:
384
344
 
385
345
  ```typescript
386
346
  const packageUrl = new URL('../', import.meta.url);
387
347
  const assetsUrl = new URL('assets/<@SCOPE>/<LIB_NAME>/', packageUrl);
388
348
 
389
- // for --target browser
390
- const asset = await fetch(new URL('<ASSET>', assetsUrl)).then(r => r.json());
349
+ // for `--target browser` and `--target node` (isomorphic)
350
+ const assetUrl = new URL('<ASSET>', assetsUrl);
351
+ const asset = await fetch(assetUrl).then(response => response.body);
391
352
 
392
- // for --target node
353
+ // for `--target node` only
393
354
  import { readFile } from 'fs/promises';
394
355
  import { fileURLToPath } from 'url';
395
- const asset = JSON.parse(await readFile(fileURLToPath(new URL('<ASSET>', assetsUrl)), 'utf-8'));
356
+ const assetUrl = new URL('<ASSET>', assetsUrl);
357
+ const assetPath = fileURLToPath(assetUrl);
358
+ const asset = await readFile(assetPath);
359
+ ```
360
+
361
+ The generated `./src/constants.ts` scaffolds the isomorphic approach and `./constants` is configured as an additional entry point in `package.json` for direct imports:
362
+
363
+ ```json
364
+ {
365
+ // ... ,
366
+ "exports": {
367
+ // ... ,
368
+ "./constants": {
369
+ "entrypoint": "./src/constants.ts",
370
+ "types": "./dist/constants.d.ts",
371
+ "browser": "./dist/constants.bundle.js",
372
+ "import": "./dist/constants.bundle.js"
373
+ }
374
+ },
375
+ // ... ,
376
+ }
396
377
  ```
397
378
 
398
379
  #### README statement for library consumers
@@ -400,7 +381,7 @@ const asset = JSON.parse(await readFile(fileURLToPath(new URL('<ASSET>', assetsU
400
381
  ```markdown
401
382
  ## Asset resolution
402
383
 
403
- This library resolves assets at runtime using `import.meta.url`. If you bundle this library into your application, copy `node_modules/<@SCOPE>/<LIB_NAME>/assets/<@SCOPE>/<LIB_NAME>/` into your build output directory alongside your bundle.
384
+ This library resolves assets at runtime using `import.meta.url`. If you include this library into your bundle, copy `node_modules/<@SCOPE>/<LIB_NAME>/assets/<@SCOPE>/<LIB_NAME>/` to your output directory as `assets/<@SCOPE>/<LIB_NAME>/`.
404
385
  ```
405
386
 
406
387
  #### When the library is bundled by the consumer
@@ -418,9 +399,34 @@ consumer output/
418
399
 
419
400
  From the bundle's perspective `assets/<@SCOPE>/<LIB_NAME>/` is at the same directory level as `bundle.js`, so `new URL('assets/<@SCOPE>/<LIB_NAME>/...', import.meta.url)` resolves correctly. No code configuration is needed - only the file copy.
420
401
 
402
+ ## `"bin"` field in `package.json`
403
+
404
+ For CLI packages, add the following to `package.json`:
405
+
406
+ ```json
407
+ {
408
+ // ... ,
409
+ "bin": "./dist/cli.bundle.js",
410
+ "scripts": {
411
+ // ... ,
412
+ "build": "... && bun run build:cli-bundle",
413
+ "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
414
+ }
415
+ }
416
+ ```
417
+
418
+ `src/cli.ts` must begin with a hashbang so the OS knows which interpreter to invoke when the binary is executed directly. Bun preserves it in the bundled output.
419
+
420
+ ```typescript
421
+ #!/usr/bin/env node
422
+ ```
423
+
424
+ If the package exports a CLI only and is not intended to be imported in other packages, the `exports` field can be omitted.
425
+
421
426
  # DevOps
422
427
 
423
428
  ```bash
429
+ bun update
424
430
  bun install
425
431
 
426
432
  bun run clean
package/buildinfo.txt CHANGED
@@ -1 +1 @@
1
- 0.7.5+df15511
1
+ 0.8.0+545e022
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temir.ra/create-ts-lib",
3
- "version": "0.7.5",
3
+ "version": "0.8.0",
4
4
  "description": "A template for a distributable TypeScript library package.",
5
5
  "author": "temir.ra",
6
6
  "license": "MIT",
@@ -43,6 +43,6 @@
43
43
  },
44
44
  "devDependencies": {
45
45
  "@types/bun": "latest",
46
- "typescript": "^6.0.2"
46
+ "typescript": "^6.0.3"
47
47
  }
48
48
  }
@@ -23,6 +23,7 @@
23
23
  # DevOps
24
24
 
25
25
  ```bash
26
+ bun update
26
27
  bun install
27
28
 
28
29
  bun run clean
@@ -66,6 +67,8 @@ bun publish --registry https://registry.npmjs.org/ --access public
66
67
 
67
68
  ### Custom registry
68
69
 
70
+ Publish to a custom registry.
71
+
69
72
  ```bash
70
73
  # placeholder:
71
74
  # <SCOPE_WITHOUT_AT: <SCOPE_WITHOUT_AT>
@@ -19,7 +19,13 @@
19
19
  "entrypoint": "./src/index.ts",
20
20
  "types": "./dist/index.d.ts",
21
21
  "browser": "./dist/index.bundle.js",
22
- "import": "./dist/index.js"
22
+ "import": "./dist/index.bundle.js"
23
+ },
24
+ "./constants": {
25
+ "entrypoint": "./src/constants.ts",
26
+ "types": "./dist/constants.d.ts",
27
+ "browser": "./dist/constants.bundle.js",
28
+ "import": "./dist/constants.bundle.js"
23
29
  }
24
30
  },
25
31
  "imports": {
@@ -42,11 +48,12 @@
42
48
  "clean": "bun run clean:dist && bun run clean:tsbuildinfo",
43
49
  "tests": "bun test",
44
50
  "prebuild": "bun run buildinfo",
45
- "build": "bun run build:bundle",
46
- "build:bundle": "bun run scripts/build-bundle.ts"
51
+ "build": "bun run build:bundle && bun run build:tsc",
52
+ "build:bundle": "bun run scripts/build-bundle.ts",
53
+ "build:tsc": "tsc --project tsconfig.build.json"
47
54
  },
48
55
  "devDependencies": {
49
56
  "@types/bun": "latest",
50
- "typescript": "^6.0.2"
57
+ "typescript": "^6.0.3"
51
58
  }
52
59
  }
@@ -0,0 +1,3 @@
1
+ export const packageUrl: URL = new URL('../', import.meta.url);
2
+ export const buildinfoUrl: URL = new URL('buildinfo.txt', packageUrl);
3
+ export const distUrl: URL = new URL('dist/', packageUrl);
@@ -16,7 +16,7 @@ function readBuildinfo(): string {
16
16
 
17
17
  describe('buildInfo', () => {
18
18
 
19
- it('should be a valid semver string', () => {
19
+ it('MUST be a valid semver string', () => {
20
20
  expect(readBuildinfo()).toMatch(SEMVER_REGEX);
21
21
  });
22
22
 
@@ -0,0 +1,21 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src/",
5
+ "module": "nodenext",
6
+ "moduleResolution": "nodenext",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "emitDeclarationOnly": true,
10
+ "outDir": "./dist/"
11
+ },
12
+ "include": [
13
+ "src/**/*.ts"
14
+ ],
15
+ "exclude": [
16
+ "node_modules/",
17
+ "dist/",
18
+ "tests/",
19
+ "scripts/"
20
+ ]
21
+ }
@@ -19,11 +19,7 @@
19
19
  "bun"
20
20
  ],
21
21
  "forceConsistentCasingInFileNames": true,
22
- "resolveJsonModule": true,
23
- "declaration": true,
24
- "declarationMap": true,
25
- "emitDeclarationOnly": true,
26
- "outDir": "./dist"
22
+ "resolveJsonModule": true
27
23
  },
28
24
  "include": [
29
25
  "scripts/**/*.ts",
@@ -32,7 +28,7 @@
32
28
  "tests/**/*.ts"
33
29
  ],
34
30
  "exclude": [
35
- "node_modules",
36
- "dist"
31
+ "node_modules/",
32
+ "dist/"
37
33
  ]
38
34
  }