@temir.ra/create-ts-lib 0.8.4 → 0.9.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 +11 -0
- package/README.md +29 -26
- package/buildinfo.txt +1 -1
- package/dist/cli.bundle.js +1 -3
- package/dist/cli.bundle.js.map +5 -9
- package/package.json +4 -3
- package/scripts/build-bundle.ts +75 -58
- package/template/package.json +3 -2
- package/template/scripts/build-bundle.ts +75 -58
- package/template/tests/buildinfo.test.ts +1 -0
- package/template/tsconfig.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Version 0
|
|
2
2
|
|
|
3
|
+
## 0.9.1
|
|
4
|
+
|
|
5
|
+
1. Updated from `template@0.2.1` template.
|
|
6
|
+
|
|
7
|
+
## 0.9.0
|
|
8
|
+
|
|
9
|
+
1. Switched to `esbuild` for bundling.
|
|
10
|
+
2. Switched to `@types/node` for type definitions.
|
|
11
|
+
3. Updated documentation to reflect the `esbuild` and `@types/node` changes.
|
|
12
|
+
4. Synced with `template@0.2.0-pre.5` template.
|
|
13
|
+
|
|
3
14
|
## 0.8.4
|
|
4
15
|
|
|
5
16
|
1. Fixed CDN rewrite plugin filter.
|
package/README.md
CHANGED
|
@@ -27,25 +27,21 @@ A template for TypeScript libraries distributed via npm-compatible registries. P
|
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
# placeholder:
|
|
30
|
-
# <TEMPLATE_PACKAGE: @temir.ra/create-ts-lib
|
|
31
|
-
# <TEMPLATE_NAME: @temir.ra/ts-lib
|
|
32
30
|
# <NEW_PACKAGE: <NEW_PACKAGE>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
# <TEMPLATE_PACKAGE_NAME: @temir.ra/create-ts-lib
|
|
32
|
+
# <TEMPLATE_NAME: @temir.ra/ts-lib
|
|
33
|
+
|
|
34
|
+
mkdir -p <NEW_PACKAGE>
|
|
35
|
+
cd <NEW_PACKAGE>
|
|
37
36
|
|
|
38
|
-
#
|
|
37
|
+
# print the latest version
|
|
39
38
|
bun info "@temir.ra/create-ts-lib" version
|
|
40
|
-
bun create --no-install --no-git "@temir.ra/ts-lib<@_VERSION>" <NEW_PACKAGE>
|
|
41
39
|
|
|
42
|
-
#
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
# create/update a package from the template in the current directory
|
|
41
|
+
bun create --no-install --no-git "@temir.ra/ts-lib@latest" .
|
|
42
|
+
|
|
43
|
+
# set metadata in package.json
|
|
46
44
|
|
|
47
|
-
# templates only copy files, run install and any setup scripts manually
|
|
48
|
-
cd <NEW_PACKAGE>
|
|
49
45
|
bun install
|
|
50
46
|
```
|
|
51
47
|
|
|
@@ -53,22 +49,18 @@ bun install
|
|
|
53
49
|
|
|
54
50
|
The following sections explain the configurations and conventions baked into the generated package. Useful when adapting it to fit specific needs.
|
|
55
51
|
|
|
56
|
-
The
|
|
52
|
+
The major addition compared to the [`workspace` template](https://www.npmjs.com/package/@temir.ra/create-workspace) is a build pipeline for distributing the library. Two build strategies are supported:
|
|
57
53
|
|
|
58
|
-
- **Bundling** (`scripts/build-bundle.ts`) -
|
|
59
|
-
- **TSC compilation** (`tsconfig.build.json` + `build:tsc`) -
|
|
54
|
+
- **Bundling** (`scripts/build-bundle.ts`) - bundles the library to ESM and IIFE formats using [`esbuild`](https://esbuild.github.io/).
|
|
55
|
+
- **TSC compilation** (`tsconfig.build.json` + `build:tsc`) - compiles the library to declaration files and ESM JavaScript using [`tsc`](https://www.typescriptlang.org/docs/handbook/compiler-options.html).
|
|
60
56
|
|
|
61
57
|
Both strategies can be combined.
|
|
62
58
|
|
|
63
59
|
## `package.json`
|
|
64
60
|
|
|
65
|
-
Selected fields are documented in the [`
|
|
66
|
-
|
|
67
|
-
See npmjs documentation on [package.json](https://docs.npmjs.com/cli/v11/configuring-npm/package-json) for detailed explanations of all fields.
|
|
61
|
+
Selected fields are documented in the [`workspace` template README](https://www.npmjs.com/package/@temir.ra/create-workspace#packagejson).
|
|
68
62
|
|
|
69
|
-
The following
|
|
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.
|
|
63
|
+
The following fields are specific to this template:
|
|
72
64
|
|
|
73
65
|
```json
|
|
74
66
|
{
|
|
@@ -150,8 +142,15 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
|
|
|
150
142
|
"build:tsc": "tsc --project tsconfig.build.json",
|
|
151
143
|
|
|
152
144
|
// bundles the CLI into a single file for distribution; requires the "bin" field to be set to the bundled output
|
|
153
|
-
"build:cli-bundle": "
|
|
145
|
+
"build:cli-bundle": "esbuild src/cli.ts --outdir=dist --entry-names=[dir]/[name].bundle --platform=node --format=esm --bundle --minify --sourcemap=external"
|
|
146
|
+
|
|
147
|
+
},
|
|
154
148
|
|
|
149
|
+
"devDependencies": {
|
|
150
|
+
"@types/bun": "latest",
|
|
151
|
+
"@types/node": "latest",
|
|
152
|
+
"esbuild": "latest",
|
|
153
|
+
"typescript": "^6.0.3"
|
|
155
154
|
}
|
|
156
155
|
|
|
157
156
|
}
|
|
@@ -159,9 +158,11 @@ The generated package is pre-configured with `build:bundle` only. See [TSC Compi
|
|
|
159
158
|
|
|
160
159
|
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
160
|
|
|
161
|
+
`"@types/bun": "latest"` is required to run tests.
|
|
162
|
+
|
|
162
163
|
## Script `scripts/build-bundle.ts`
|
|
163
164
|
|
|
164
|
-
Bundles the library to ESM and IIFE formats
|
|
165
|
+
Bundles the library to ESM and IIFE formats using `esbuild`. 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
|
|
|
166
167
|
Import specifiers can be rewritten to CDN URLs via `scripts/cdn-rewrite-map.json`.
|
|
167
168
|
|
|
@@ -181,7 +182,7 @@ Maps import specifiers to CDN URLs. During bundling, matching specifiers in sour
|
|
|
181
182
|
|
|
182
183
|
`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
|
|
|
184
|
-
See [`
|
|
185
|
+
See [`workspace` template 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
|
|
|
186
187
|
```json
|
|
187
188
|
{
|
|
@@ -360,6 +361,8 @@ const asset = await readFile(assetPath);
|
|
|
360
361
|
|
|
361
362
|
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
|
|
|
364
|
+
⚠️ Beware that `import.meta.url` is replaced by `document.currentScript.src` during bundling in IIFE format since it is available only under ESM (research "import.meta vs document.currentScript.src").
|
|
365
|
+
|
|
363
366
|
```json
|
|
364
367
|
{
|
|
365
368
|
// ... ,
|
package/buildinfo.txt
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.9.1+037ba94
|
package/dist/cli.bundle.js
CHANGED
|
@@ -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)}
|
package/dist/cli.bundle.js.map
CHANGED
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
|
|
6
|
-
|
|
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,12 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temir.ra/create-ts-lib",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "A template for a distributable TypeScript library package.",
|
|
5
5
|
"author": "temir.ra",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"typescript",
|
|
9
|
-
"bun",
|
|
10
9
|
"template",
|
|
11
10
|
"library"
|
|
12
11
|
],
|
|
@@ -39,10 +38,12 @@
|
|
|
39
38
|
"tests": "bun test",
|
|
40
39
|
"prebuild": "bun run buildinfo",
|
|
41
40
|
"build": "bun run build:cli-bundle",
|
|
42
|
-
"build:cli-bundle": "
|
|
41
|
+
"build:cli-bundle": "esbuild src/cli.ts --outdir=dist --entry-names=[dir]/[name].bundle --platform=node --format=esm --bundle --minify --sourcemap=external"
|
|
43
42
|
},
|
|
44
43
|
"devDependencies": {
|
|
45
44
|
"@types/bun": "latest",
|
|
45
|
+
"@types/node": "latest",
|
|
46
|
+
"esbuild": "latest",
|
|
46
47
|
"typescript": "^6.0.3"
|
|
47
48
|
}
|
|
48
49
|
}
|
package/scripts/build-bundle.ts
CHANGED
|
@@ -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?:
|
|
23
|
-
devDependencies?:
|
|
24
|
-
peerDependencies?:
|
|
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]
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
|
89
|
-
if (
|
|
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
|
|
96
|
-
|
|
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
|
|
106
|
+
return cdnUrl;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
const
|
|
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:
|
|
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 =
|
|
109
|
-
|
|
131
|
+
const url = resolveVersionInCdnUrl(importSpecifier, urlTemplate);
|
|
132
|
+
console.log(`[cdn-rewrite plugin] '${importSpecifier}' → '${url}'`);
|
|
110
133
|
|
|
111
134
|
const escapedSpecifier = importSpecifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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: [
|
|
142
|
-
});
|
|
160
|
+
plugins: [esbuildLog, cdnRewrite],
|
|
143
161
|
|
|
144
|
-
|
|
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
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
|
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
|
}
|
package/template/package.json
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
"author": "",
|
|
6
6
|
"license": "",
|
|
7
7
|
"keywords": [
|
|
8
|
-
"typescript"
|
|
9
|
-
"bun"
|
|
8
|
+
"typescript"
|
|
10
9
|
],
|
|
11
10
|
"repository": {
|
|
12
11
|
"type": "git",
|
|
@@ -54,6 +53,8 @@
|
|
|
54
53
|
},
|
|
55
54
|
"devDependencies": {
|
|
56
55
|
"@types/bun": "latest",
|
|
56
|
+
"@types/node": "latest",
|
|
57
|
+
"esbuild": "latest",
|
|
57
58
|
"typescript": "^6.0.3"
|
|
58
59
|
}
|
|
59
60
|
}
|
|
@@ -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?:
|
|
23
|
-
devDependencies?:
|
|
24
|
-
peerDependencies?:
|
|
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]
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
|
89
|
-
if (
|
|
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
|
|
96
|
-
|
|
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
|
|
106
|
+
return cdnUrl;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
const
|
|
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:
|
|
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 =
|
|
109
|
-
|
|
131
|
+
const url = resolveVersionInCdnUrl(importSpecifier, urlTemplate);
|
|
132
|
+
console.log(`[cdn-rewrite plugin] '${importSpecifier}' → '${url}'`);
|
|
110
133
|
|
|
111
134
|
const escapedSpecifier = importSpecifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
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: [
|
|
142
|
-
});
|
|
160
|
+
plugins: [esbuildLog, cdnRewrite],
|
|
143
161
|
|
|
144
|
-
|
|
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
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
|
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
|
}
|