@temir.ra/create-template 0.1.9 → 0.1.10

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,9 @@
1
1
  # Version 0
2
2
 
3
+ ## 0.1.10
4
+
5
+ 1. Synced with `ts-lib` template.
6
+
3
7
  ## 0.1.9
4
8
 
5
9
  1. Fixed template assets paths.
package/buildinfo.txt CHANGED
@@ -1 +1 @@
1
- 0.1.9+edda801
1
+ 0.1.10+55bf9cf
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temir.ra/create-template",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "A template for a template package.",
5
5
  "author": "temir.ra",
6
6
  "license": "MIT",
@@ -28,16 +28,14 @@ function getManifest(packageIdentifier?: string): PackageManifest {
28
28
 
29
29
  const manifestPath = packageIdentifier
30
30
  ? join('node_modules', packageIdentifier, 'package.json')
31
- : 'package.json';
31
+ : 'package.json'
32
+ ;
32
33
 
33
34
  let manifest: PackageManifest;
34
35
  try {
35
36
  manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
36
37
  } catch {
37
- if (packageIdentifier)
38
- throw new Error(`[scripts/build-bundle.ts] Could not read manifest for '${packageIdentifier}' at '${manifestPath}'.`);
39
- else
40
- throw new Error(`[scripts/build-bundle.ts] Could not read package manifest at '${manifestPath}'.`);
38
+ throw new Error(`[scripts/build-bundle.ts] Failed to read package manifest at '${manifestPath}'.`);
41
39
  }
42
40
 
43
41
  return manifest;
@@ -104,7 +102,7 @@ const cdnRewritePlugin = {
104
102
  console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
105
103
  }
106
104
 
107
- build.onResolve({ filter: /\*/ }, (args: any) => {
105
+ build.onResolve({ filter: /.*/ }, (args: any) => {
108
106
  const url = resolved.get(args.path);
109
107
  if (url) return { path: url, external: true };
110
108
  });
@@ -116,6 +114,8 @@ const cdnRewritePlugin = {
116
114
  const entrypoints = getManifestEntrypoints(getManifest());
117
115
  console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
118
116
 
117
+ const omitIife = process.argv.includes('--omit-iife');
118
+
119
119
  let buildResult;
120
120
 
121
121
  console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
@@ -139,23 +139,25 @@ if (!buildResult.success) {
139
139
  }
140
140
  console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
141
141
 
142
- console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
143
- buildResult = await Bun.build({
144
- entrypoints,
145
- outdir: 'dist',
146
- naming: '[dir]/[name].iife.[ext]',
147
- target: 'browser',
148
- format: 'iife',
149
- minify: true,
150
- sourcemap: 'external',
151
- plugins: [cdnRewritePlugin],
152
- });
153
-
154
- if (!buildResult.success) {
155
- console.error('[scripts/build-bundle.ts] Build failed:');
156
- for (const message of buildResult.logs) {
157
- console.error(message);
142
+ if (!omitIife) {
143
+ console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
144
+ buildResult = await Bun.build({
145
+ entrypoints,
146
+ outdir: 'dist',
147
+ naming: '[dir]/[name].iife.[ext]',
148
+ target: 'browser',
149
+ format: 'iife',
150
+ minify: true,
151
+ sourcemap: 'external',
152
+ plugins: [cdnRewritePlugin],
153
+ });
154
+
155
+ if (!buildResult.success) {
156
+ console.error('[scripts/build-bundle.ts] Build failed:');
157
+ for (const message of buildResult.logs) {
158
+ console.error(message);
159
+ }
160
+ process.exit(1);
158
161
  }
159
- process.exit(1);
162
+ console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
160
163
  }
161
- console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
@@ -28,16 +28,14 @@ function getManifest(packageIdentifier?: string): PackageManifest {
28
28
 
29
29
  const manifestPath = packageIdentifier
30
30
  ? join('node_modules', packageIdentifier, 'package.json')
31
- : 'package.json';
31
+ : 'package.json'
32
+ ;
32
33
 
33
34
  let manifest: PackageManifest;
34
35
  try {
35
36
  manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
36
37
  } catch {
37
- if (packageIdentifier)
38
- throw new Error(`[scripts/build-bundle.ts] Could not read manifest for '${packageIdentifier}' at '${manifestPath}'.`);
39
- else
40
- throw new Error(`[scripts/build-bundle.ts] Could not read package manifest at '${manifestPath}'.`);
38
+ throw new Error(`[scripts/build-bundle.ts] Failed to read package manifest at '${manifestPath}'.`);
41
39
  }
42
40
 
43
41
  return manifest;
@@ -104,7 +102,7 @@ const cdnRewritePlugin = {
104
102
  console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
105
103
  }
106
104
 
107
- build.onResolve({ filter: /\*/ }, (args: any) => {
105
+ build.onResolve({ filter: /.*/ }, (args: any) => {
108
106
  const url = resolved.get(args.path);
109
107
  if (url) return { path: url, external: true };
110
108
  });
@@ -116,6 +114,8 @@ const cdnRewritePlugin = {
116
114
  const entrypoints = getManifestEntrypoints(getManifest());
117
115
  console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
118
116
 
117
+ const omitIife = process.argv.includes('--omit-iife');
118
+
119
119
  let buildResult;
120
120
 
121
121
  console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
@@ -139,23 +139,25 @@ if (!buildResult.success) {
139
139
  }
140
140
  console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
141
141
 
142
- console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
143
- buildResult = await Bun.build({
144
- entrypoints,
145
- outdir: 'dist',
146
- naming: '[dir]/[name].iife.[ext]',
147
- target: 'browser',
148
- format: 'iife',
149
- minify: true,
150
- sourcemap: 'external',
151
- plugins: [cdnRewritePlugin],
152
- });
153
-
154
- if (!buildResult.success) {
155
- console.error('[scripts/build-bundle.ts] Build failed:');
156
- for (const message of buildResult.logs) {
157
- console.error(message);
142
+ if (!omitIife) {
143
+ console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
144
+ buildResult = await Bun.build({
145
+ entrypoints,
146
+ outdir: 'dist',
147
+ naming: '[dir]/[name].iife.[ext]',
148
+ target: 'browser',
149
+ format: 'iife',
150
+ minify: true,
151
+ sourcemap: 'external',
152
+ plugins: [cdnRewritePlugin],
153
+ });
154
+
155
+ if (!buildResult.success) {
156
+ console.error('[scripts/build-bundle.ts] Build failed:');
157
+ for (const message of buildResult.logs) {
158
+ console.error(message);
159
+ }
160
+ process.exit(1);
158
161
  }
159
- process.exit(1);
162
+ console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
160
163
  }
161
- console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
@@ -14,9 +14,9 @@ function readBuildinfo(): string {
14
14
  return readFileSync(fileURLToPath(buildinfoUrl), 'utf-8').trim();
15
15
  }
16
16
 
17
- describe('buildInfo', () => {
17
+ describe('buildinfo.txt', () => {
18
18
 
19
- it('MUST be a valid semver string', () => {
19
+ it('MUST contain a valid semver string', () => {
20
20
  expect(readBuildinfo()).toMatch(SEMVER_REGEX);
21
21
  });
22
22
 
@@ -1,157 +0,0 @@
1
- # Version 0
2
-
3
- ## 0.8.1
4
-
5
- 1. Added `DOM` to the `lib` array in the generated `tsconfig.json`.
6
-
7
- ## 0.8.0
8
-
9
- 1. Updated wording in the Publish section of the generated README.
10
- 2. `build:tsc` step is now generated per default.
11
- 3. Added `./constants` entrypoint to `package.json`.
12
-
13
- ## 0.7.6
14
-
15
- 1. Updated `typescript` to `6.0.3`.
16
- 2. Cleaned up minor `README.md` inconsistencies.
17
- 3. Aligned wording with [`RFC 2119`](https://datatracker.ietf.org/doc/html/rfc2119).
18
- 4. Updated files from `template` template.
19
-
20
- ## 0.7.5
21
-
22
- 1. Updated files from `@temir.ra/template@0.1.6` template.
23
-
24
- ## 0.7.4
25
-
26
- 1. Updated `keywords` in `template/package.json`.
27
- 2. Restored docs for `build*` and `tests` `package.json` scripts in `README.md`.
28
- 3. Reduced `scripts/dev.ts` section to a DevOps command.
29
- 4. Added clarification on the `files` field recommendation for `tests/` in the README.
30
- 5. Updated from `@temir.ra/template@0.1.5` template.
31
-
32
- ## 0.7.3
33
-
34
- 1. Updated from `@temir.ra/template@0.1.4` template.
35
-
36
- ## 0.7.2
37
-
38
- 1. Cleaned up `*-template.*` files from the template directory.
39
-
40
- ## 0.7.1
41
-
42
- 1. Updated `template/` files from `@temir.ra/workspace@0.4.1` template.
43
-
44
- ## 0.7.0
45
-
46
- 1. Updated `.gitignore`: added `bun.lock`, `buildinfo-template.txt`, `CHANGELOG-template.md`, `README-template.md`; replaced nested `template/.gitignore` with `template/gitignore` to prevent template files from being excluded during distribution.
47
- 2. Removed `CLAUDE.md`, `AGENTS.md`, and `src/dev.ts` from root and template.
48
- 3. Overhauled the generated `package.json`: added `private: false`; removed `sideEffects: false`; added build scripts to published `files`; updated `clean:tsbuildinfo` to `rm -f *.tsbuildinfo || true`; renamed `build:lib-bundle` to `build:bundle`; removed `build:lib` and `dev` scripts; added `reinstall` script; bumped typescript to `^6.0.2`.
49
- 4. Updated the generated `tsconfig.json`: changed `target` to `ESNext`; removed `DOM` from `lib`; added `types: ["bun"]`.
50
- 5. Removed generated `tsconfig.build.json`; TSC compilation is now opt-in and documented in `README.md`.
51
- 6. Renamed `scripts/build-lib-bundle.ts` to `scripts/build-bundle.ts` in root and template; updated to produce ESM and IIFE browser bundles; added to published `files`; updated CDN rewrite plugin filter.
52
- 7. Extracted path constants from `src/cli.ts` to `src/constants.ts`; CLI now copies `README.md` as `README-template.md` to generated projects; improved error message for missing package name argument; moved `template/src/dev.ts` to `template/scripts/dev.ts`.
53
- 8. Updated `scripts/buildinfo.ts` in root and template: reads version from `package.json` instead of `npm_package_version` env var; handles pre-existing `+` in version string.
54
- 9. Refactored `template/tests/buildinfo.test.ts` to use a proper semver regex.
55
- 10. Overhauled `README.md`: new documentation structure with build strategies overview, `package.json` and `tsconfig.json` sections referencing `create-workspace`, opt-in TSC Compilation section, `bin` field documentation, `scripts/dev.ts` section; removed `CLAUDE.md`/`AGENTS.md` section.
56
- 11. Updated from `@temir.ra/template@0.1.3` template.
57
-
58
- ## 0.6.3
59
-
60
- 1. Cleaned up dormant package scripts.
61
- 2. Cleaned up minor `README.md` inconsistencies.
62
-
63
- ## 0.6.2
64
-
65
- 1. Updated `clean:tsbuildinfo` script to remove both `tsconfig.tsbuildinfo` and `tsconfig.build.tsbuildinfo`.
66
-
67
- ## 0.6.1
68
-
69
- 1. Cleaned up dormant imports.
70
- 2. Cleaned up / updated minor `README.md` inconsistencies.
71
- 3. Updated placeholders in `README.md` in the **Asset resolution** section.
72
- 4. Removed **Asset resolution** section from the generated `README.md`, as the operational passage is given in the template `README.md`.
73
- 5. Removed **AI Assistant Context** section from the `README.md` files.
74
- 7. Cleaned up **Publish** section in the `README.md`.
75
-
76
- ## 0.6.0
77
-
78
- 1. Updated documentation and configs to TypeScript 6.
79
-
80
- ## 0.5.0
81
-
82
- 1. Changed `buildinfo.txt` generation and testing to align with [https://semver.org](https://semver.org).
83
-
84
- ## 0.4.1
85
-
86
- 1. Fixed `destinationPath` resolution in `cli.ts` to use the full resolved path instead of just the basename.
87
-
88
- ## 0.4.0
89
-
90
- 1. Added support for scoped package names in the CLI argument parsing and asset resolution.
91
-
92
- ## 0.3.1-pre.1 (unreleased)
93
-
94
- 1. Removed `dev.ts` file.
95
-
96
- ## 0.3.0
97
-
98
- 1. Removed AI Assistant Context files to be generated by the user with the provided prompts in the README.
99
-
100
- ## 0.2.8 (unreleased)
101
-
102
- 1. CLI now copies root `README.md` into the generated project as `README-template.md`.
103
- 2. Added `README-template.md` to `template/gitignore`.
104
- 3. Added `# AI Assistant Context` section to root `README.md` and `template/README.md` with prompts for generating AI coding assistant context files.
105
- 4. Revised Change Management step 6 in root `README.md` and `template/README.md`.
106
- 5. `.gitignore`'ing `bun.lock`.
107
-
108
- ## 0.2.8-pre.2
109
-
110
- 1. Removed `sideEffects` property from `package.json` as it is not a standard field.
111
- 2. Added references to npmjs and typescriptlang documentation for `package.json` and `tsconfig.json` in the README.
112
-
113
- ## 0.2.7
114
-
115
- 1. Changed `filter` property in `cdnRewritePlugin` in `scripts/build-lib-bundle.ts` to take import identifiers into account that do not have file extensions.
116
- 2. Changed `buildinfo.txt` generation in `scripts/buildinfo.ts` to read the version from `package.json` instead of relying on the `npm_package_version` environment variable. Enables correct version capture in monorepo setups.
117
-
118
- ## 0.2.6
119
-
120
- 1. Minor ToC and typo fixes in both README.md files (root and template).
121
- 2. Revised the Publish section in both README.md files.
122
-
123
- ## 0.2.5
124
-
125
- 1. Minor README updates.
126
- 2. Fixed `buildinfo.txt` in published package.
127
- 3. Fixed `buildinfo.test.ts` regex to accept semver prerelease identifiers.
128
-
129
- ## 0.2.4
130
-
131
- 1. Documented template caching in the Quick Start section with commands to pin the version or clear the cache.
132
- 2. Minor README updates: Revised Asset Resolution sections in root and template; Added introductory paragraph to Documentation section;
133
- 3. Moved git-upstream to `https://git.chimps.quest/trs/create-ts-lib.git`.
134
-
135
- ## 0.2.3
136
-
137
- 1. Updated change management workflow in `README.md` and `template/README.md`: build step now happens after merge (not before PR), so `buildinfo.txt` captures the correct git hash and artifacts are up to date before publish.
138
- 2. Added Change Management section to root and template `CLAUDE.md`.
139
-
140
- ## 0.2.2
141
-
142
- 1. Fixed `CHANGELOG.md` and `buildinfo.txt` copy paths in `cli.ts`: they were resolved relative to `template/` instead of the package root, causing the copy to fail. Refactored URL/path construction to derive all paths from a single `packageUrl`, eliminating redundant `fileURLToPath` calls at each copy site.
143
- 2. Added `buildinfo-template.txt` and `CHANGELOG-template.md` to `template/gitignore` so generated libraries do not track template files.
144
- 3. Added `example/` to the root `.gitignore` to exclude local test scaffold output.
145
- 4. Added a `bun run dist/cli.bundle.js -- example` snippet to the DevOps section of the README for quick local testing.
146
-
147
- ## 0.2.1
148
-
149
- 1. Added asset resolution documentation to root README: scoped asset folder convention, inline `import.meta.url` resolution, `fetch()` for isomorphic I/O, setup steps, checklist, and consumer README statement.
150
- 2. Updated template README with a reference to the asset resolution docs in the create-ts-lib README.
151
- 3. Updated both `CLAUDE.md` files.
152
- 4. Updated both `dev.ts` files to use inline `new URL('../', import.meta.url)`.
153
- 5. Removed `src/urls.ts` from root and template (not needed - inline resolution is sufficient).
154
-
155
- ## 0.1.0
156
-
157
- 1. First version of the template.
@@ -1,458 +0,0 @@
1
- # Introduction
2
-
3
- A template for TypeScript libraries distributed via npm-compatible registries. Provides TypeScript configuration, build tooling for ESM and bundled outputs, and build metadata generation.
4
-
5
- ## Table of Contents
6
-
7
- 1. [Quick Start](#quick-start)
8
- 2. [Documentation](#documentation)
9
- 1. [`package.json`](#packagejson)
10
- 2. [Script `scripts/build-bundle.ts`](#script-scriptsbuild-bundlets)
11
- 1. [CDN Map `scripts/cdn-rewrite-map.json`](#cdn-map-scriptscdn-rewrite-mapjson)
12
- 3. [`tsconfig.build.json`](#tsconfigbuildjson)
13
- 4. [Asset Resolution](#asset-resolution)
14
- 1. [Externalized - loaded from CDN or `node_modules/`](#externalized---loaded-from-cdn-or-node_modules)
15
- 2. [Bundled - absorbed into the consumer's output](#bundled---absorbed-into-the-consumers-output)
16
- 3. [Contract](#contract)
17
- 1. [Scoped assets directory convention](#scoped-assets-directory-convention)
18
- 2. [Accessing assets](#accessing-assets)
19
- 3. [README statement for library consumers](#readme-statement-for-library-consumers)
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)
22
- 3. [DevOps](#devops)
23
- 1. [Change Management](#change-management)
24
- 2. [Publish](#publish)
25
-
26
- # Quick Start
27
-
28
- ```bash
29
- # placeholder:
30
- # <TEMPLATE_PACKAGE: @temir.ra/create-ts-lib
31
- # <TEMPLATE_NAME: @temir.ra/ts-lib
32
- # <NEW_PACKAGE: <NEW_PACKAGE>
33
- # is used as:
34
- # - the path where the package is created
35
- # - the "name" field in the generated package.json
36
- # <@_VERSION: <@_VERSION>
37
-
38
- # pinned version
39
- bun info "@temir.ra/create-ts-lib" version
40
- bun create --no-install --no-git "@temir.ra/ts-lib<@_VERSION>" <NEW_PACKAGE>
41
-
42
- # latest
43
- # clear the cache to pick up the latest version
44
- bun pm cache rm
45
- bun create --no-install --no-git "@temir.ra/ts-lib" <NEW_PACKAGE>
46
-
47
- # templates only copy files, run install and any setup scripts manually
48
- cd <NEW_PACKAGE>
49
- bun install
50
- ```
51
-
52
- # Documentation
53
-
54
- The following sections explain the configurations and conventions baked into the generated package. Useful when adapting it to fit specific needs.
55
-
56
- The central addition over [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace) is a build pipeline for distributing the library. Two build strategies are supported:
57
-
58
- - **Bundling** (`scripts/build-bundle.ts`) - generated by default; bundles the library to ESM and IIFE formats.
59
- - **TSC compilation** (`tsconfig.build.json` + `build:tsc`) - optional, not generated by default; compiles source files one-for-one to ESM JavaScript and declaration files.
60
-
61
- Both strategies can be combined.
62
-
63
- ## `package.json`
64
-
65
- Selected fields are documented in the [`create-workspace` README](https://www.npmjs.com/package/@temir.ra/create-workspace#packagejson).
66
-
67
- See npmjs documentation on [package.json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for detailed explanations of all fields.
68
-
69
- The following lists the additions and overrides relative to [`create-workspace`](https://www.npmjs.com/package/@temir.ra/create-workspace#packagejson).
70
-
71
- The generated package is pre-configured with `build:bundle` only. See [TSC Compilation](#tsc-compilation) and [`"bin"` field](#bin-field-in-packagejson) for extending it.
72
-
73
- ```json
74
- {
75
-
76
- // ... ,
77
-
78
- // the package is anticipated to be published
79
- "private": false,
80
-
81
- // treats all .js files as ES modules; use .cjs extension for CommonJS files
82
- "type": "module",
83
-
84
- // package entry points
85
- // multiple entry points can be configured (".", "./module/", etc.)
86
- //
87
- // scripts/build-bundle.ts (non-standard) export condition:
88
- // "entrypoint" - locates the source entry point for bundling
89
- //
90
- // standard export conditions:
91
- // "types" - TypeScript consumers; resolves to the declaration files;
92
- // "browser" - browser bundler consumers; resolves to the bundled output
93
- // "import" - ESM consumers; resolves to the bundled/compiled output
94
- "exports": {
95
- ".": {
96
- "entrypoint": "./src/index.ts",
97
- "types": "./dist/index.d.ts",
98
- "browser": "./dist/index.bundle.js",
99
- "import": "./dist/index.bundle.js"
100
- }
101
- },
102
-
103
- // convenience alias for source-execution only - does NOT survive transpilation or bundling
104
- // NOT for use in source files compiled by tsconfig.build.json
105
- // the .js extension is required in import statements (nodenext compliance)
106
- "imports": {
107
- "#src/*.js": "./src/*.ts"
108
- },
109
-
110
- // CLI entry point
111
- "bin": "./dist/cli.bundle.js",
112
-
113
- // files to include in the published package
114
- "files": [
115
- "scripts/buildinfo.ts",
116
- "scripts/build-bundle.ts",
117
- "scripts/cdn-rewrite-map.json",
118
- "CHANGELOG.md",
119
- "buildinfo.txt",
120
- "dist/",
121
- "tests/"
122
- ],
123
-
124
- "scripts": {
125
-
126
- // ... ,
127
-
128
- // removes the dist/ directory generated by the build steps
129
- "clean:dist": "rm -rf dist/",
130
-
131
- // removes .tsbuildinfo files generated by TypeScript's incremental build feature
132
- "clean:tsbuildinfo": "rm -f *.tsbuildinfo || true",
133
-
134
- // convenience script to run the clean steps in sequence
135
- "clean": "bun run clean:dist && bun run clean:tsbuildinfo",
136
-
137
- // discovers and runs test files
138
- "tests": "bun test",
139
-
140
- // executed before build; generates buildinfo.txt
141
- "prebuild": "bun run buildinfo",
142
-
143
- // convenience script to run the build steps in sequence
144
- "build": "bun run build:bundle && bun run build:tsc && bun run build:cli-bundle",
145
-
146
- // bundles the library into ESM and IIFE formats for distribution
147
- "build:bundle": "bun run scripts/build-bundle.ts",
148
-
149
- // compiles the library to declaration files and ESM JavaScript in dist/
150
- "build:tsc": "tsc --project tsconfig.build.json",
151
-
152
- // bundles the CLI into a single file for distribution; requires the "bin" field to be set to the bundled output
153
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
154
-
155
- }
156
-
157
- }
158
- ```
159
-
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`.
161
-
162
- ## Script `scripts/build-bundle.ts`
163
-
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.
165
-
166
- Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
167
-
168
- ### CDN Map `scripts/cdn-rewrite-map.json`
169
-
170
- Maps import specifiers to CDN URLs. During bundling, matching specifiers in source files are rewritten to their CDN equivalents.
171
-
172
- `<VERSION>` in a URL is replaced with the version of the matching package from `package.json`.
173
-
174
- ```json
175
- {
176
- "import-specifier": "https://cdn.jsdelivr.net/npm/package-name@<VERSION>/dist/index.bundle.js"
177
- }
178
- ```
179
-
180
- ## `tsconfig.build.json`
181
-
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.
183
-
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.
185
-
186
- ```json
187
- {
188
-
189
- "extends": "./tsconfig.json",
190
-
191
- "compilerOptions": {
192
-
193
- // narrows root to src/ for distribution output
194
- "rootDir": "./src/",
195
-
196
- // nodenext enforces strict ESM compliance; imports must use explicit .js file extensions
197
- "module": "nodenext",
198
- "moduleResolution": "nodenext",
199
-
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/"
211
-
212
- },
213
-
214
- // include only src/ files for distribution
215
- "include": [
216
- "src/**/*.ts"
217
- ],
218
- // exclude development files and directories from distribution
219
- "exclude": [
220
- "node_modules/",
221
- "dist/",
222
- "tests/",
223
- "scripts/"
224
- ]
225
-
226
- }
227
- ```
228
-
229
- ### `package.json`
230
-
231
- ```json
232
- {
233
- // ... ,
234
- "scripts": {
235
- // ... ,
236
- "build": "... && bun run build:tsc",
237
- "build:tsc": "tsc --project tsconfig.build.json"
238
- }
239
- }
240
- ```
241
-
242
- Exports condition `import` may point to the compiled output instead of the bundled output `./dist/index.bundle.js` if `"emitDeclarationOnly": false`:
243
-
244
- ```json
245
- {
246
- // ... ,
247
- "exports": {
248
- ".": {
249
- // ... ,
250
- "import": "./dist/index.js"
251
- }
252
- },
253
- // ... ,
254
- }
255
- ```
256
-
257
- When `"declaration": true`, then exports condition `types` can be added to point to the declaration files:
258
-
259
- ```json
260
- {
261
- // ... ,
262
- "exports": {
263
- ".": {
264
- // ... ,
265
- "types": "./dist/index.d.ts",
266
- // ... ,
267
- }
268
- },
269
- // ... ,
270
- }
271
- ```
272
-
273
- ## Asset Resolution
274
-
275
- The key question to ask is: **does my library retain its own URL at runtime?** Everything else follows from it.
276
-
277
- ```bash
278
- # placeholder:
279
- # <@SCOPE: <@SCOPE>
280
- # <LIB_NAME: <LIB_NAME>
281
- # <VERSION: <VERSION>
282
- ```
283
-
284
- ### Externalized - loaded from CDN or `node_modules/`
285
-
286
- The consumer does not bundle the library. It is loaded as a discrete module at runtime. Module identity is preserved regardless of the URL form:
287
-
288
- ```
289
- https://cdn.jsdelivr.net/npm/<@SCOPE>/<LIB_NAME>@<VERSION>/dist/index.js
290
- file:///project/node_modules/<@SCOPE>/<LIB_NAME>/dist/index.js
291
- https://your-own-cdn.com/<LIB_NAME>/index.js
292
- ```
293
-
294
- `import.meta.url` is reliable in all these cases. `fetch()` is the correct I/O mechanism because it accepts both `https://` and `file://` URLs, making it universally correct for isomorphic (`--target node` or `--target browser`) libraries.
295
-
296
- ### Bundled - absorbed into the consumer's output
297
-
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.
299
-
300
- ### Contract
301
-
302
- If the library has runtime assets, the following contract applies:
303
-
304
- **The library must:**
305
- 1. **Place assets in a scoped assets directory** - see [Scoped assets directory convention](#scoped-assets-directory-convention) below.
306
- 2. **Access assets via `import.meta.url`** - see [Accessing assets](#accessing-assets) below.
307
- 3. **Document the bundled case** - see [README statement for library consumers](#readme-statement-for-library-consumers) below.
308
-
309
- **The consumer must,**
310
- - **when loading the library externalized:** do nothing - the library's `import.meta.url` works as-is, and assets load from their original location (CDN or `node_modules/`).
311
- - **when bundling the library:**
312
- 1. **Copy the assets** - see [When the library is bundled by the consumer](#when-the-library-is-bundled-by-the-consumer) below.
313
- 2. **Ensure the assets are served**
314
- - if the consumer is a web server, ensure the copied assets are served as static files
315
- - if the consumer is a bundler, ensure the copied assets are included in the output directory
316
-
317
- #### Scoped assets directory convention
318
-
319
- Place all runtime assets under a scoped directory that mirrors the package name:
320
-
321
- ```
322
- assets/
323
- └── <@SCOPE>/
324
- └── <LIB_NAME>/
325
- └── ...
326
- ```
327
-
328
- Add `assets/` to the `files` field in `package.json` so that the assets are included in the published package:
329
-
330
- ```json
331
- {
332
- // ... ,
333
- "files": [
334
- // ... ,
335
- "assets/"
336
- ],
337
- // ... ,
338
- }
339
- ```
340
-
341
- #### Accessing assets
342
-
343
- Construct asset URLs directly from `import.meta.url`:
344
-
345
- ```typescript
346
- const packageUrl = new URL('../', import.meta.url);
347
- const assetsUrl = new URL('assets/<@SCOPE>/<LIB_NAME>/', packageUrl);
348
-
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);
352
-
353
- // for `--target node` only
354
- import { readFile } from 'fs/promises';
355
- import { fileURLToPath } from 'url';
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
- }
377
- ```
378
-
379
- #### README statement for library consumers
380
-
381
- ```markdown
382
- ## Asset resolution
383
-
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>/`.
385
- ```
386
-
387
- #### When the library is bundled by the consumer
388
-
389
- The consumer must copy the assets into their build output at the same relative path the library expects:
390
-
391
- ```
392
- consumer output/
393
- ├── bundle.js ← import.meta.url points here
394
- └── assets/
395
- └── <@SCOPE>/
396
- └── <LIB_NAME>/
397
- └── ... ← copied; relative path preserved
398
- ```
399
-
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.
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
-
426
- # DevOps
427
-
428
- ```bash
429
- bun update
430
- bun install
431
-
432
- bun run clean
433
- bun run build
434
- bun run tests
435
-
436
- # see publish section for publish instructions
437
- ```
438
-
439
- ## Change Management
440
-
441
- 1. Create a new branch for the change.
442
- 2. Make the changes and commit.
443
- 3. Bump the version in [`package.json`](package.json).
444
- 4. Add an entry for the new version in [`CHANGELOG.md`](CHANGELOG.md).
445
- 5. Pull request the branch.
446
- 6. Ensure package artifacts are current.
447
- 7. Publish.
448
-
449
- ## Publish
450
-
451
- Publish to the public npm registry.
452
-
453
- ```powershell
454
- # authenticate
455
- npm login
456
- # publish
457
- bun publish --registry https://registry.npmjs.org/ --access public
458
- ```
@@ -1 +0,0 @@
1
- 0.8.0+545e022