@temir.ra/create-template 0.1.11 → 0.2.1

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,16 @@
1
1
  # Version 0
2
2
 
3
+ ## 0.2.1
4
+
5
+ 1. Updated Quick Start section.
6
+
7
+ ## 0.2.0
8
+
9
+ 1. Synced with `ts-lib@0.9.0` template.
10
+ 2. Switched to `esbuild` for bundling.
11
+ 3. Updated Quick Start section to reflect typical usage patterns.
12
+ 4. Updated files from self.
13
+
3
14
  ## 0.1.11
4
15
 
5
16
  1. Synced with `ts-lib@0.8.4` template.
package/README.md CHANGED
@@ -14,25 +14,21 @@
14
14
 
15
15
  ```bash
16
16
  # placeholder:
17
- # <TEMPLATE_PACKAGE: @temir.ra/create-template
18
- # <TEMPLATE_NAME: @temir.ra/template
19
17
  # <NEW_PACKAGE: <NEW_PACKAGE>
20
- # is used as:
21
- # - the path where the package is created
22
- # - the "name" field in the generated package.json
23
- # <@_VERSION: <@_VERSION>
18
+ # <TEMPLATE_PACKAGE_NAME: @temir.ra/create-template
19
+ # <TEMPLATE_NAME: @temir.ra/template
20
+
21
+ mkdir -p <NEW_PACKAGE>
22
+ cd <NEW_PACKAGE>
24
23
 
25
- # pinned version
24
+ # print the latest version
26
25
  bun info "@temir.ra/create-template" version
27
- bun create --no-install --no-git "@temir.ra/template<@_VERSION>" <NEW_PACKAGE>
28
26
 
29
- # latest
30
- # clear the cache to pick up the latest version
31
- bun pm cache rm
32
- bun create --no-install --no-git "@temir.ra/template" <NEW_PACKAGE>
27
+ # create/update a package from the template in the current directory
28
+ bun create --no-install --no-git "@temir.ra/template@latest" .
29
+
30
+ # set metadata in package.json
33
31
 
34
- # templates only copy files, run install and any setup scripts manually
35
- cd <NEW_PACKAGE>
36
32
  bun install
37
33
  ```
38
34
 
package/buildinfo.txt CHANGED
@@ -1 +1 @@
1
- 0.1.11+05a1e68
1
+ 0.2.1+57fdfbd
@@ -1,4 +1,2 @@
1
1
  #!/usr/bin/env node
2
- import{cpSync as a,readFileSync as g,renameSync as U,writeFileSync as d}from"fs";import{resolve as r}from"path";var n=new URL("../",import.meta.url),i=new URL("buildinfo.txt",n),u=new URL("dist/",n),l=new URL("template/",n),m=new URL("CHANGELOG.md",n),p=new URL("README.md",n);try{let t=process.argv[2];if(!t)throw Error('First argument must be the package name (e.g. "my-package" or "@my-scope/my-package").');let o=t.replace(/\\/g,"/"),e=r(process.cwd(),o);a(l,e,{recursive:!0}),a(m,r(e,"CHANGELOG-template.md")),a(i,r(e,"buildinfo-template.txt")),a(p,r(e,"README-template.md"));let c=r(e,"package.json"),s=JSON.parse(g(c,"utf-8"));s.name=o,d(c,JSON.stringify(s,null,2)),U(r(e,"gitignore"),r(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${o}'.`)}catch(t){let o=t instanceof Error?t:Error(String(t));console.error("Error:",o.message),process.exit(1)}
3
-
4
- //# debugId=EF224A42FEFD5AB864756E2164756E21
2
+ import{cpSync as a,readFileSync as g,renameSync as U,writeFileSync as d}from"fs";import{resolve as r}from"path";var n=new URL("../",import.meta.url),i=new URL("buildinfo.txt",n),u=new URL("dist/",n),l=new URL("template/",n),m=new URL("CHANGELOG.md",n),p=new URL("README.md",n);try{let t=process.argv[2];if(!t)throw new Error('First argument must be the package name (e.g. "my-package" or "@my-scope/my-package").');let o=t.replace(/\\/g,"/"),e=r(process.cwd(),o);a(l,e,{recursive:!0}),a(m,r(e,"CHANGELOG-template.md")),a(i,r(e,"buildinfo-template.txt")),a(p,r(e,"README-template.md"));let c=r(e,"package.json"),s=JSON.parse(g(c,"utf-8"));s.name=o,d(c,JSON.stringify(s,null,2)),U(r(e,"gitignore"),r(e,".gitignore")),console.log(`Template has been successfully instantiated at '${e}' with package name '${o}'.`)}catch(t){let o=t instanceof Error?t:new Error(String(t));console.error("Error:",o.message),process.exit(1)}
@@ -1,11 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["..\\src\\cli.ts", "..\\src\\constants.ts"],
4
- "sourcesContent": [
5
- "#!/usr/bin/env node\r\n\r\nimport { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';\r\nimport { resolve } from 'path';\r\nimport {\r\n templateUrl,\r\n changelogUrl,\r\n buildinfoUrl,\r\n readmeUrl\r\n} from './constants.js';\r\n\r\n\r\ntry {\r\n\r\n const packageNameArgument = process.argv[2];\r\n if (!packageNameArgument)\r\n throw new Error('First argument must be the package name (e.g. \"my-package\" or \"@my-scope/my-package\").');\r\n const packageName = packageNameArgument.replace(/\\\\/g, '/');\r\n\r\n const destinationPath = resolve(process.cwd(), packageName);\r\n\r\n cpSync(templateUrl, destinationPath, { recursive: true });\r\n cpSync(changelogUrl, resolve(destinationPath, 'CHANGELOG-template.md'));\r\n cpSync(buildinfoUrl, resolve(destinationPath, 'buildinfo-template.txt'));\r\n cpSync(readmeUrl, resolve(destinationPath, 'README-template.md'));\r\n\r\n const packageJsonPath = resolve(destinationPath, 'package.json');\r\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\r\n packageJson.name = packageName;\r\n writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));\r\n\r\n renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));\r\n\r\n console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);\r\n\r\n}\r\ncatch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n console.error('Error:', err.message);\r\n process.exit(1);\r\n}\r\n",
6
- "export const packageUrl: URL = new URL('../', import.meta.url);\r\nexport const buildinfoUrl: URL = new URL('buildinfo.txt', packageUrl);\r\nexport const distUrl: URL = new URL('dist/', packageUrl);\r\n\r\nexport const templateUrl: URL = new URL('template/', packageUrl);\r\nexport const changelogUrl: URL = new URL('CHANGELOG.md', packageUrl);\r\nexport const readmeUrl: URL = new URL('README.md', packageUrl);\r\n"
7
- ],
8
- "mappings": ";AAEA,iBAAS,kBAAQ,gBAAc,mBAAY,WAC3C,kBAAS,aCHF,IAAM,EAAkB,IAAI,IAAI,MAAO,YAAY,GAAG,EAChD,EAAoB,IAAI,IAAI,gBAAiB,CAAU,EACvD,EAAe,IAAI,IAAI,QAAS,CAAU,EAE1C,EAAmB,IAAI,IAAI,YAAa,CAAU,EAClD,EAAoB,IAAI,IAAI,eAAgB,CAAU,EACtD,EAAiB,IAAI,IAAI,YAAa,CAAU,EDM7D,GAAI,CAEA,IAAM,EAAsB,QAAQ,KAAK,GACzC,GAAI,CAAC,EACD,MAAU,MAAM,wFAAwF,EAC5G,IAAM,EAAc,EAAoB,QAAQ,MAAO,GAAG,EAEpD,EAAkB,EAAQ,QAAQ,IAAI,EAAG,CAAW,EAE1D,EAAO,EAAa,EAAiB,CAAE,UAAW,EAAK,CAAC,EACxD,EAAO,EAAc,EAAQ,EAAiB,uBAAuB,CAAC,EACtE,EAAO,EAAc,EAAQ,EAAiB,wBAAwB,CAAC,EACvE,EAAO,EAAW,EAAQ,EAAiB,oBAAoB,CAAC,EAEhE,IAAM,EAAkB,EAAQ,EAAiB,cAAc,EACzD,EAAc,KAAK,MAAM,EAAa,EAAiB,OAAO,CAAC,EACrE,EAAY,KAAO,EACnB,EAAc,EAAiB,KAAK,UAAU,EAAa,KAAM,CAAC,CAAC,EAEnE,EAAW,EAAQ,EAAiB,WAAW,EAAG,EAAQ,EAAiB,YAAY,CAAC,EAExF,QAAQ,IAAI,mDAAmD,yBAAuC,KAAe,EAGzH,MAAO,EAAO,CACV,IAAM,EAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,EACpE,QAAQ,MAAM,SAAU,EAAI,OAAO,EACnC,QAAQ,KAAK,CAAC",
9
- "debugId": "EF224A42FEFD5AB864756E2164756E21",
10
- "names": []
11
- }
3
+ "sources": ["../src/cli.ts", "../src/constants.ts"],
4
+ "sourcesContent": ["#!/usr/bin/env node\r\n\r\nimport { cpSync, readFileSync, renameSync, writeFileSync } from 'fs';\r\nimport { resolve } from 'path';\r\nimport {\r\n templateUrl,\r\n changelogUrl,\r\n buildinfoUrl,\r\n readmeUrl\r\n} from './constants.js';\r\n\r\n\r\ntry {\r\n\r\n const packageNameArgument = process.argv[2];\r\n if (!packageNameArgument)\r\n throw new Error('First argument must be the package name (e.g. \"my-package\" or \"@my-scope/my-package\").');\r\n const packageName = packageNameArgument.replace(/\\\\/g, '/');\r\n\r\n const destinationPath = resolve(process.cwd(), packageName);\r\n\r\n cpSync(templateUrl, destinationPath, { recursive: true });\r\n cpSync(changelogUrl, resolve(destinationPath, 'CHANGELOG-template.md'));\r\n cpSync(buildinfoUrl, resolve(destinationPath, 'buildinfo-template.txt'));\r\n cpSync(readmeUrl, resolve(destinationPath, 'README-template.md'));\r\n\r\n const packageJsonPath = resolve(destinationPath, 'package.json');\r\n const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));\r\n packageJson.name = packageName;\r\n writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));\r\n\r\n renameSync(resolve(destinationPath, 'gitignore'), resolve(destinationPath, '.gitignore'));\r\n\r\n console.log(`Template has been successfully instantiated at '${destinationPath}' with package name '${packageName}'.`);\r\n\r\n}\r\ncatch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n console.error('Error:', err.message);\r\n process.exit(1);\r\n}\r\n", "export const packageUrl: URL = new URL('../', import.meta.url);\r\nexport const buildinfoUrl: URL = new URL('buildinfo.txt', packageUrl);\r\nexport const distUrl: URL = new URL('dist/', packageUrl);\r\n\r\nexport const templateUrl: URL = new URL('template/', packageUrl);\r\nexport const changelogUrl: URL = new URL('CHANGELOG.md', packageUrl);\r\nexport const readmeUrl: URL = new URL('README.md', packageUrl);\r\n"],
5
+ "mappings": ";AAEA,OAAS,UAAAA,EAAQ,gBAAAC,EAAc,cAAAC,EAAY,iBAAAC,MAAqB,KAChE,OAAS,WAAAC,MAAe,OCHjB,IAAMC,EAAkB,IAAI,IAAI,MAAO,YAAY,GAAG,EAChDC,EAAoB,IAAI,IAAI,gBAAiBD,CAAU,EACvDE,EAAe,IAAI,IAAI,QAASF,CAAU,EAE1CG,EAAmB,IAAI,IAAI,YAAaH,CAAU,EAClDI,EAAoB,IAAI,IAAI,eAAgBJ,CAAU,EACtDK,EAAiB,IAAI,IAAI,YAAaL,CAAU,EDM7D,GAAI,CAEA,IAAMM,EAAsB,QAAQ,KAAK,CAAC,EAC1C,GAAI,CAACA,EACD,MAAM,IAAI,MAAM,wFAAwF,EAC5G,IAAMC,EAAcD,EAAoB,QAAQ,MAAO,GAAG,EAEpDE,EAAkBC,EAAQ,QAAQ,IAAI,EAAGF,CAAW,EAE1DG,EAAOC,EAAaH,EAAiB,CAAE,UAAW,EAAK,CAAC,EACxDE,EAAOE,EAAcH,EAAQD,EAAiB,uBAAuB,CAAC,EACtEE,EAAOG,EAAcJ,EAAQD,EAAiB,wBAAwB,CAAC,EACvEE,EAAOI,EAAWL,EAAQD,EAAiB,oBAAoB,CAAC,EAEhE,IAAMO,EAAkBN,EAAQD,EAAiB,cAAc,EACzDQ,EAAc,KAAK,MAAMC,EAAaF,EAAiB,OAAO,CAAC,EACrEC,EAAY,KAAOT,EACnBW,EAAcH,EAAiB,KAAK,UAAUC,EAAa,KAAM,CAAC,CAAC,EAEnEG,EAAWV,EAAQD,EAAiB,WAAW,EAAGC,EAAQD,EAAiB,YAAY,CAAC,EAExF,QAAQ,IAAI,mDAAmDA,CAAe,wBAAwBD,CAAW,IAAI,CAEzH,OACOa,EAAO,CACV,IAAMC,EAAMD,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,EACpE,QAAQ,MAAM,SAAUC,EAAI,OAAO,EACnC,QAAQ,KAAK,CAAC,CAClB",
6
+ "names": ["cpSync", "readFileSync", "renameSync", "writeFileSync", "resolve", "packageUrl", "buildinfoUrl", "distUrl", "templateUrl", "changelogUrl", "readmeUrl", "packageNameArgument", "packageName", "destinationPath", "resolve", "cpSync", "templateUrl", "changelogUrl", "buildinfoUrl", "readmeUrl", "packageJsonPath", "packageJson", "readFileSync", "writeFileSync", "renameSync", "error", "err"]
7
+ }
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@temir.ra/create-template",
3
- "version": "0.1.11",
3
+ "version": "0.2.1",
4
4
  "description": "A template for a template package.",
5
5
  "author": "temir.ra",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "typescript",
9
- "bun",
10
- "template"
9
+ "template-template"
11
10
  ],
12
11
  "repository": {
13
12
  "type": "git",
@@ -38,10 +37,12 @@
38
37
  "tests": "bun test",
39
38
  "prebuild": "bun run buildinfo",
40
39
  "build": "bun run build:cli-bundle",
41
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
40
+ "build:cli-bundle": "esbuild src/cli.ts --outdir=dist --entry-names=[dir]/[name].bundle --platform=node --format=esm --bundle --minify --sourcemap=external"
42
41
  },
43
42
  "devDependencies": {
44
43
  "@types/bun": "latest",
44
+ "@types/node": "latest",
45
+ "esbuild": "latest",
45
46
  "typescript": "^6.0.3"
46
47
  }
47
48
  }
@@ -1,5 +1,15 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
+ import {
4
+ build,
5
+ type BuildFailure,
6
+ type OnResolveArgs,
7
+ type OnResolveResult,
8
+ type Plugin as EsbuildPlugin,
9
+ type PluginBuild,
10
+ type BuildOptions,
11
+ type BuildResult
12
+ } from 'esbuild';
3
13
 
4
14
  import CDN_REWRITE_MAP from './cdn-rewrite-map.json';
5
15
 
@@ -11,17 +21,15 @@ interface ExportConditions {
11
21
  browser?: string;
12
22
  import?: string;
13
23
  }
14
-
15
- interface DependencyMap {
24
+ interface Dependency {
16
25
  [key: string]: string;
17
26
  }
18
-
19
27
  interface PackageManifest {
20
28
  version: string;
21
29
  exports?: Record<string, ExportConditions>;
22
- dependencies?: DependencyMap;
23
- devDependencies?: DependencyMap;
24
- peerDependencies?: DependencyMap;
30
+ dependencies?: Dependency;
31
+ devDependencies?: Dependency;
32
+ peerDependencies?: Dependency;
25
33
  }
26
34
 
27
35
  function getManifest(packageIdentifier?: string): PackageManifest {
@@ -32,6 +40,7 @@ function getManifest(packageIdentifier?: string): PackageManifest {
32
40
  ;
33
41
 
34
42
  let manifest: PackageManifest;
43
+
35
44
  try {
36
45
  manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
37
46
  } catch {
@@ -41,24 +50,22 @@ function getManifest(packageIdentifier?: string): PackageManifest {
41
50
  return manifest;
42
51
 
43
52
  }
44
-
45
53
  function getManifestEntrypoints(packageManifest: PackageManifest): string[] {
46
54
 
47
55
  const exports = packageManifest.exports;
48
56
  if (!exports)
49
- throw new Error(`[scripts/build-bundle.ts] No 'exports' field found in the given package manifest.`);
57
+ throw new Error(`[scripts/build-bundle.ts] Failed to read entrypoints from package manifest: 'exports' field is missing.`);
50
58
 
51
59
  const entrypoints = Object.entries(exports)
52
60
  .map(([key, conditions]) => {
53
61
  if (!conditions.entrypoint)
54
- throw new Error(`[scripts/build-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
62
+ throw new Error(`[scripts/build-bundle.ts] Failed to read entrypoints from package manifest: 'entrypoint' condition is missing for export '${key}'.`);
55
63
  return conditions.entrypoint;
56
64
  });
57
65
 
58
66
  return entrypoints;
59
67
 
60
68
  }
61
-
62
69
  function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string): string {
63
70
 
64
71
  let version: string | undefined;
@@ -72,12 +79,12 @@ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string
72
79
 
73
80
  version = dependencies[packageIdentifier];
74
81
  if (!version)
75
- throw new Error(`[scripts/build-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
82
+ throw new Error(`[scripts/build-bundle.ts] Failed to read version for package '${packageIdentifier}': package is not listed in dependencies.`);
76
83
 
77
84
  }
78
85
  else {
79
86
  if (!manifest.version)
80
- throw new Error('[scripts/build-bundle.ts] Package manifest does not contain a version field.');
87
+ throw new Error('[scripts/build-bundle.ts] Failed to read package version from manifest: version field is missing.');
81
88
  version = manifest.version;
82
89
  }
83
90
 
@@ -85,36 +92,52 @@ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string
85
92
 
86
93
  }
87
94
 
88
- function resolveCdnUrl(importSpecifier: string, urlTemplate: string): string {
89
- if (urlTemplate.includes('<VERSION>')) {
95
+ function resolveVersionInCdnUrl(importSpecifier: string, cdnUrl: string): string {
96
+ if (cdnUrl.includes('<VERSION>')) {
90
97
  const manifest = getManifest();
91
98
  const version = getPackageVersion(manifest, importSpecifier);
92
99
  let resolvedVersion = version;
93
100
  if (resolvedVersion.startsWith('workspace:')) resolvedVersion = resolvedVersion.replace(/^workspace:/, '');
94
101
  if (resolvedVersion.startsWith('^') || resolvedVersion.startsWith('~')) resolvedVersion = resolvedVersion.substring(1);
95
- if (resolvedVersion.length !== 0)
96
- return urlTemplate.replace('<VERSION>', resolvedVersion);
102
+ if (resolvedVersion.length === 0)
103
+ throw new Error(`[scripts/build-bundle.ts] Failed to resolve version for package '${importSpecifier}': resolved version is empty.`);
104
+ return cdnUrl.replace('<VERSION>', resolvedVersion);
97
105
  }
98
- return urlTemplate;
106
+ return cdnUrl;
99
107
  }
100
108
 
101
- const cdnRewritePlugin = {
109
+ const esbuildLog: EsbuildPlugin = {
110
+ name: 'esbuild-log',
111
+ setup(build: PluginBuild) {
112
+ const format = build.initialOptions.format || 'unknown';
113
+ build.onStart(() => {
114
+ console.log(`[esbuild-log plugin] ${format} build started...`);
115
+ });
116
+ build.onEnd((result: BuildResult<BuildOptions>) => {
117
+ if (result.errors.length > 0) {
118
+ console.error(`[esbuild-log plugin] ${format} build failed.`);
119
+ } else {
120
+ console.log(`[esbuild-log plugin] ${format} build finished.`);
121
+ }
122
+ });
123
+ }
124
+ }
125
+ const cdnRewrite: EsbuildPlugin = {
102
126
  name: 'cdn-rewrite',
103
- setup(build: any) {
127
+ setup(build: PluginBuild) {
104
128
 
105
- const resolved: Record<string, string> = {};
106
129
  for (const [importSpecifier, urlTemplate] of Object.entries(CDN_REWRITE_MAP) as [string, string][]) {
107
130
 
108
- const url = resolveCdnUrl(importSpecifier, urlTemplate);
109
- resolved[importSpecifier] = url;
131
+ const url = resolveVersionInCdnUrl(importSpecifier, urlTemplate);
132
+ console.log(`[cdn-rewrite plugin] '${importSpecifier}' → '${url}'`);
110
133
 
111
134
  const escapedSpecifier = importSpecifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
112
- console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
113
-
114
- build.onResolve({ filter: new RegExp(`^${escapedSpecifier}$`) }, (args: any) => {
115
- const url = resolved[args.path];
116
- if (url) return { path: url, external: true };
117
- });
135
+ build.onResolve(
136
+ { filter: new RegExp(`^${escapedSpecifier}$`) },
137
+ (args: OnResolveArgs): OnResolveResult | undefined => {
138
+ return { path: url, external: true };
139
+ }
140
+ );
118
141
 
119
142
  }
120
143
 
@@ -125,50 +148,44 @@ const cdnRewritePlugin = {
125
148
  const entrypoints = getManifestEntrypoints(getManifest());
126
149
  console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
127
150
 
128
- const omitIife = process.argv.includes('--omit-iife');
129
-
130
- let buildResult;
131
-
132
- console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
133
- buildResult = await Bun.build({
134
- entrypoints,
135
- outdir: 'dist',
136
- naming: '[dir]/[name].bundle.[ext]',
137
- target: 'browser',
151
+ const buildOptions: BuildOptions = {
152
+ entryPoints: entrypoints,
153
+ outdir: 'dist/',
154
+ entryNames: '[dir]/[name].bundle',
155
+ platform: 'browser',
138
156
  format: 'esm',
157
+ bundle: true,
139
158
  minify: true,
140
159
  sourcemap: 'external',
141
- plugins: [cdnRewritePlugin],
142
- });
160
+ plugins: [esbuildLog, cdnRewrite],
143
161
 
144
- if (!buildResult.success) {
162
+ };
163
+
164
+ try {
165
+ await build(buildOptions);
166
+ } catch (error) {
145
167
  console.error('[scripts/build-bundle.ts] Build failed:');
146
- for (const message of buildResult.logs) {
168
+ for (const message of (error as BuildFailure).errors) {
147
169
  console.error(message);
148
170
  }
149
171
  process.exit(1);
150
172
  }
151
- console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
152
173
 
174
+ const omitIife = process.argv.includes('--omit-iife');
153
175
  if (!omitIife) {
154
- console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
155
- buildResult = await Bun.build({
156
- entrypoints,
157
- outdir: 'dist',
158
- naming: '[dir]/[name].iife.[ext]',
159
- target: 'browser',
160
- format: 'iife',
161
- minify: true,
162
- sourcemap: 'external',
163
- plugins: [cdnRewritePlugin],
164
- });
165
-
166
- if (!buildResult.success) {
176
+ try {
177
+ await build({
178
+ ...buildOptions,
179
+ entryNames: '[dir]/[name].iife.bundle',
180
+ format: 'iife',
181
+ banner: { js: 'var __importMetaUrl = document.currentScript && document.currentScript.src || \'\';' },
182
+ define: { 'import.meta.url': '__importMetaUrl' },
183
+ });
184
+ } catch (error) {
167
185
  console.error('[scripts/build-bundle.ts] Build failed:');
168
- for (const message of buildResult.logs) {
186
+ for (const message of (error as BuildFailure).errors) {
169
187
  console.error(message);
170
188
  }
171
189
  process.exit(1);
172
190
  }
173
- console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
174
191
  }
@@ -16,25 +16,21 @@
16
16
 
17
17
  ```bash
18
18
  # placeholder:
19
- # <TEMPLATE_PACKAGE: <TEMPLATE_PACKAGE>
20
- # <TEMPLATE_NAME: <TEMPLATE_NAME>
21
19
  # <NEW_PACKAGE: <NEW_PACKAGE>
22
- # is used as:
23
- # - the path where the package is created
24
- # - the "name" field in the generated package.json
25
- # <@_VERSION: <@_VERSION>
20
+ # <TEMPLATE_PACKAGE_NAME: <TEMPLATE_PACKAGE_NAME>
21
+ # <TEMPLATE_NAME: <TEMPLATE_NAME>
22
+
23
+ mkdir -p <NEW_PACKAGE>
24
+ cd <NEW_PACKAGE>
26
25
 
27
- # pinned version
28
- bun info "<TEMPLATE_PACKAGE>" version
29
- bun create --no-install --no-git "<TEMPLATE_NAME><@_VERSION>" <NEW_PACKAGE>
26
+ # print the latest version
27
+ bun info "<TEMPLATE_PACKAGE_NAME>" version
30
28
 
31
- # latest
32
- # clear the cache to pick up the latest version
33
- bun pm cache rm
34
- bun create --no-install --no-git "<TEMPLATE_NAME>" <NEW_PACKAGE>
29
+ # create/update a package from the template in the current directory
30
+ bun create --no-install --no-git "<TEMPLATE_NAME>@latest" .
31
+
32
+ # set metadata in package.json
35
33
 
36
- # templates only copy files, run install and any setup scripts manually
37
- cd <NEW_PACKAGE>
38
34
  bun install
39
35
  ```
40
36
 
@@ -6,7 +6,6 @@
6
6
  "license": "",
7
7
  "keywords": [
8
8
  "typescript",
9
- "bun",
10
9
  "template"
11
10
  ],
12
11
  "repository": {
@@ -38,10 +37,12 @@
38
37
  "tests": "bun test",
39
38
  "prebuild": "bun run buildinfo",
40
39
  "build": "bun run build:cli-bundle",
41
- "build:cli-bundle": "bun build src/cli.ts --entry-naming \"[dir]/[name].bundle.[ext]\" --outdir dist --target node --format esm --minify --sourcemap=external"
40
+ "build:cli-bundle": "esbuild src/cli.ts --outdir=dist --entry-names=[dir]/[name].bundle --platform=node --format=esm --bundle --minify --sourcemap=external"
42
41
  },
43
42
  "devDependencies": {
44
43
  "@types/bun": "latest",
44
+ "@types/node": "latest",
45
+ "esbuild": "latest",
45
46
  "typescript": "^6.0.3"
46
47
  }
47
48
  }
@@ -1,5 +1,15 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
+ import {
4
+ build,
5
+ type BuildFailure,
6
+ type OnResolveArgs,
7
+ type OnResolveResult,
8
+ type Plugin as EsbuildPlugin,
9
+ type PluginBuild,
10
+ type BuildOptions,
11
+ type BuildResult
12
+ } from 'esbuild';
3
13
 
4
14
  import CDN_REWRITE_MAP from './cdn-rewrite-map.json';
5
15
 
@@ -11,17 +21,15 @@ interface ExportConditions {
11
21
  browser?: string;
12
22
  import?: string;
13
23
  }
14
-
15
- interface DependencyMap {
24
+ interface Dependency {
16
25
  [key: string]: string;
17
26
  }
18
-
19
27
  interface PackageManifest {
20
28
  version: string;
21
29
  exports?: Record<string, ExportConditions>;
22
- dependencies?: DependencyMap;
23
- devDependencies?: DependencyMap;
24
- peerDependencies?: DependencyMap;
30
+ dependencies?: Dependency;
31
+ devDependencies?: Dependency;
32
+ peerDependencies?: Dependency;
25
33
  }
26
34
 
27
35
  function getManifest(packageIdentifier?: string): PackageManifest {
@@ -32,6 +40,7 @@ function getManifest(packageIdentifier?: string): PackageManifest {
32
40
  ;
33
41
 
34
42
  let manifest: PackageManifest;
43
+
35
44
  try {
36
45
  manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
37
46
  } catch {
@@ -41,24 +50,22 @@ function getManifest(packageIdentifier?: string): PackageManifest {
41
50
  return manifest;
42
51
 
43
52
  }
44
-
45
53
  function getManifestEntrypoints(packageManifest: PackageManifest): string[] {
46
54
 
47
55
  const exports = packageManifest.exports;
48
56
  if (!exports)
49
- throw new Error(`[scripts/build-bundle.ts] No 'exports' field found in the given package manifest.`);
57
+ throw new Error(`[scripts/build-bundle.ts] Failed to read entrypoints from package manifest: 'exports' field is missing.`);
50
58
 
51
59
  const entrypoints = Object.entries(exports)
52
60
  .map(([key, conditions]) => {
53
61
  if (!conditions.entrypoint)
54
- throw new Error(`[scripts/build-bundle.ts] Export '${key}' does not have an 'entrypoint' condition.`);
62
+ throw new Error(`[scripts/build-bundle.ts] Failed to read entrypoints from package manifest: 'entrypoint' condition is missing for export '${key}'.`);
55
63
  return conditions.entrypoint;
56
64
  });
57
65
 
58
66
  return entrypoints;
59
67
 
60
68
  }
61
-
62
69
  function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string): string {
63
70
 
64
71
  let version: string | undefined;
@@ -72,12 +79,12 @@ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string
72
79
 
73
80
  version = dependencies[packageIdentifier];
74
81
  if (!version)
75
- throw new Error(`[scripts/build-bundle.ts] Package '${packageIdentifier}' is not listed in dependencies.`);
82
+ throw new Error(`[scripts/build-bundle.ts] Failed to read version for package '${packageIdentifier}': package is not listed in dependencies.`);
76
83
 
77
84
  }
78
85
  else {
79
86
  if (!manifest.version)
80
- throw new Error('[scripts/build-bundle.ts] Package manifest does not contain a version field.');
87
+ throw new Error('[scripts/build-bundle.ts] Failed to read package version from manifest: version field is missing.');
81
88
  version = manifest.version;
82
89
  }
83
90
 
@@ -85,36 +92,52 @@ function getPackageVersion(manifest: PackageManifest, packageIdentifier?: string
85
92
 
86
93
  }
87
94
 
88
- function resolveCdnUrl(importSpecifier: string, urlTemplate: string): string {
89
- if (urlTemplate.includes('<VERSION>')) {
95
+ function resolveVersionInCdnUrl(importSpecifier: string, cdnUrl: string): string {
96
+ if (cdnUrl.includes('<VERSION>')) {
90
97
  const manifest = getManifest();
91
98
  const version = getPackageVersion(manifest, importSpecifier);
92
99
  let resolvedVersion = version;
93
100
  if (resolvedVersion.startsWith('workspace:')) resolvedVersion = resolvedVersion.replace(/^workspace:/, '');
94
101
  if (resolvedVersion.startsWith('^') || resolvedVersion.startsWith('~')) resolvedVersion = resolvedVersion.substring(1);
95
- if (resolvedVersion.length !== 0)
96
- return urlTemplate.replace('<VERSION>', resolvedVersion);
102
+ if (resolvedVersion.length === 0)
103
+ throw new Error(`[scripts/build-bundle.ts] Failed to resolve version for package '${importSpecifier}': resolved version is empty.`);
104
+ return cdnUrl.replace('<VERSION>', resolvedVersion);
97
105
  }
98
- return urlTemplate;
106
+ return cdnUrl;
99
107
  }
100
108
 
101
- const cdnRewritePlugin = {
109
+ const esbuildLog: EsbuildPlugin = {
110
+ name: 'esbuild-log',
111
+ setup(build: PluginBuild) {
112
+ const format = build.initialOptions.format || 'unknown';
113
+ build.onStart(() => {
114
+ console.log(`[esbuild-log plugin] ${format} build started...`);
115
+ });
116
+ build.onEnd((result: BuildResult<BuildOptions>) => {
117
+ if (result.errors.length > 0) {
118
+ console.error(`[esbuild-log plugin] ${format} build failed.`);
119
+ } else {
120
+ console.log(`[esbuild-log plugin] ${format} build finished.`);
121
+ }
122
+ });
123
+ }
124
+ }
125
+ const cdnRewrite: EsbuildPlugin = {
102
126
  name: 'cdn-rewrite',
103
- setup(build: any) {
127
+ setup(build: PluginBuild) {
104
128
 
105
- const resolved: Record<string, string> = {};
106
129
  for (const [importSpecifier, urlTemplate] of Object.entries(CDN_REWRITE_MAP) as [string, string][]) {
107
130
 
108
- const url = resolveCdnUrl(importSpecifier, urlTemplate);
109
- resolved[importSpecifier] = url;
131
+ const url = resolveVersionInCdnUrl(importSpecifier, urlTemplate);
132
+ console.log(`[cdn-rewrite plugin] '${importSpecifier}' → '${url}'`);
110
133
 
111
134
  const escapedSpecifier = importSpecifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
112
- console.log(`[cdn-rewrite] '${importSpecifier}' → '${url}'`);
113
-
114
- build.onResolve({ filter: new RegExp(`^${escapedSpecifier}$`) }, (args: any) => {
115
- const url = resolved[args.path];
116
- if (url) return { path: url, external: true };
117
- });
135
+ build.onResolve(
136
+ { filter: new RegExp(`^${escapedSpecifier}$`) },
137
+ (args: OnResolveArgs): OnResolveResult | undefined => {
138
+ return { path: url, external: true };
139
+ }
140
+ );
118
141
 
119
142
  }
120
143
 
@@ -125,50 +148,44 @@ const cdnRewritePlugin = {
125
148
  const entrypoints = getManifestEntrypoints(getManifest());
126
149
  console.log('[scripts/build-bundle.ts] Entrypoints:', entrypoints);
127
150
 
128
- const omitIife = process.argv.includes('--omit-iife');
129
-
130
- let buildResult;
131
-
132
- console.log('[scripts/build-bundle.ts] Starting ESM bundle build...');
133
- buildResult = await Bun.build({
134
- entrypoints,
135
- outdir: 'dist',
136
- naming: '[dir]/[name].bundle.[ext]',
137
- target: 'browser',
151
+ const buildOptions: BuildOptions = {
152
+ entryPoints: entrypoints,
153
+ outdir: 'dist/',
154
+ entryNames: '[dir]/[name].bundle',
155
+ platform: 'browser',
138
156
  format: 'esm',
157
+ bundle: true,
139
158
  minify: true,
140
159
  sourcemap: 'external',
141
- plugins: [cdnRewritePlugin],
142
- });
160
+ plugins: [esbuildLog, cdnRewrite],
143
161
 
144
- if (!buildResult.success) {
162
+ };
163
+
164
+ try {
165
+ await build(buildOptions);
166
+ } catch (error) {
145
167
  console.error('[scripts/build-bundle.ts] Build failed:');
146
- for (const message of buildResult.logs) {
168
+ for (const message of (error as BuildFailure).errors) {
147
169
  console.error(message);
148
170
  }
149
171
  process.exit(1);
150
172
  }
151
- console.log('[scripts/build-bundle.ts] ESM bundle build completed successfully.');
152
173
 
174
+ const omitIife = process.argv.includes('--omit-iife');
153
175
  if (!omitIife) {
154
- console.log('[scripts/build-bundle.ts] Starting IIFE bundle build...');
155
- buildResult = await Bun.build({
156
- entrypoints,
157
- outdir: 'dist',
158
- naming: '[dir]/[name].iife.[ext]',
159
- target: 'browser',
160
- format: 'iife',
161
- minify: true,
162
- sourcemap: 'external',
163
- plugins: [cdnRewritePlugin],
164
- });
165
-
166
- if (!buildResult.success) {
176
+ try {
177
+ await build({
178
+ ...buildOptions,
179
+ entryNames: '[dir]/[name].iife.bundle',
180
+ format: 'iife',
181
+ banner: { js: 'var __importMetaUrl = document.currentScript && document.currentScript.src || \'\';' },
182
+ define: { 'import.meta.url': '__importMetaUrl' },
183
+ });
184
+ } catch (error) {
167
185
  console.error('[scripts/build-bundle.ts] Build failed:');
168
- for (const message of buildResult.logs) {
186
+ for (const message of (error as BuildFailure).errors) {
169
187
  console.error(message);
170
188
  }
171
189
  process.exit(1);
172
190
  }
173
- console.log('[scripts/build-bundle.ts] IIFE bundle build completed successfully.');
174
191
  }
@@ -1,3 +1,4 @@
1
+ /// <reference types="bun" />
1
2
  import { describe, it, expect } from 'bun:test';
2
3
  import { readFileSync } from 'fs';
3
4
  import { fileURLToPath } from 'url';
@@ -17,7 +17,7 @@
17
17
  "composite": true,
18
18
  "skipLibCheck": true,
19
19
  "types": [
20
- "bun"
20
+ "node"
21
21
  ],
22
22
  "forceConsistentCasingInFileNames": true,
23
23
  "resolveJsonModule": true