@bunit/build 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,136 @@
1
+ # @bunit/build
2
+
3
+ > ⚡️ Zero-config TypeScript package builder powered by [**Bun**](https://bun.sh).
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Blazing Fast** - Built on Bun's native bundler and transpiler
8
+ - 📦 **Dual Mode** - Bundle mode for entry points, Transform mode for directories
9
+ - 🎯 **Zero-Config** - Smart defaults with flexible customization
10
+ - 📝 **Type Generation** - Automatic `.d.ts` declarations with unplugin-isolated-decl
11
+ - 🛠️ **CLI Tool** - Simple command-line interface
12
+ - 🚀 **Stub Mode** - Development mode for faster builds
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ bun add @bunit/build
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ### CLI
23
+
24
+ ```bash
25
+ # Build using build.config.ts
26
+ built
27
+
28
+ # Stub mode (development)
29
+ built --stub
30
+
31
+ # Bundle mode
32
+ built ./src/index.ts
33
+
34
+ # Transform mode (directory)
35
+ built ./src/lib/:./dist/lib
36
+
37
+ # Specify working directory
38
+ built --dir ./packages/my-lib
39
+ ```
40
+
41
+ ### Programmatic
42
+
43
+ ```typescript
44
+ import { build } from "@bunit/build";
45
+
46
+ await build({
47
+ entries: ["./src/index.ts"],
48
+ });
49
+ ```
50
+
51
+ ## Config
52
+
53
+ Create `build.config.ts` (or `.mjs`):
54
+
55
+ ```typescript
56
+ import { defineBuildConfig } from "@bunit/build/config";
57
+
58
+ export default defineBuildConfig({
59
+ entries: [
60
+ {
61
+ type: "bundle",
62
+ input: ["./src/index.ts", "./src/cli.ts"],
63
+ // outDir: "./dist",
64
+ // minify: false,
65
+ // stub: false,
66
+ // bun: {}, // https://bun.sh/docs/bundler
67
+ // dts: true,
68
+ },
69
+ {
70
+ type: "transform",
71
+ input: "./src/lib",
72
+ outDir: "./dist/lib",
73
+ // stub: false,
74
+ // transpiler: {},
75
+ // filter: (file) => !file.includes('.test.ts'),
76
+ // dts: true,
77
+ },
78
+ ],
79
+ hooks: {
80
+ // start: (ctx) => {},
81
+ // end: (ctx) => {},
82
+ // entries: (entries, ctx) => {},
83
+ // bunConfig: (config, ctx) => {},
84
+ // bunOutput: (config, ctx) => {},
85
+ },
86
+ });
87
+ ```
88
+
89
+ ## Stub Mode
90
+
91
+ When working on a package locally, rebuilding can be tedious. Use `stub: true` or the `--stub` CLI flag to skip the actual build and link expected dist paths to source files.
92
+
93
+ - **Bundle entries**: `.mjs` and `.d.mts` files re-export the source file
94
+ - **Transform entries**: `.mjs` files re-export from source TypeScript files
95
+
96
+ **Caveats:**
97
+
98
+ - You need a runtime that natively supports TypeScript (Bun, Deno)
99
+ - When using stub mode with transform mode, ensure your bundler can resolve `.ts` or `.mjs` extensions
100
+ - For bundle mode, if you add/remove exports, run the stub build again
101
+
102
+ ## Build Modes
103
+
104
+ ### Bundle Mode
105
+
106
+ Ideal for library entry points with dependency analysis and code splitting.
107
+
108
+ ```typescript
109
+ {
110
+ type: "bundle",
111
+ input: "./src/index.ts",
112
+ minify: true,
113
+ bun: {
114
+ sourcemap: "external",
115
+ // ... any Bun.build option
116
+ },
117
+ }
118
+ ```
119
+
120
+ ### Transform Mode
121
+
122
+ Preserves file structure for transforming directories.
123
+
124
+ ```typescript
125
+ {
126
+ type: "transform",
127
+ input: "./src/lib",
128
+ outDir: "./dist/lib",
129
+ filter: (file) => !file.includes('.test.ts'),
130
+ stub: false,
131
+ }
132
+ ```
133
+
134
+ ## License
135
+
136
+ [MIT](../../LICENSE) © [Demo Macro](https://www.demomacro.com/)
@@ -0,0 +1,23 @@
1
+ // @bun
2
+ var x=import.meta.require;import{resolve as P}from"path";function _(Q,V){let H=P(Q),I=V||process.cwd(),Y=H.replace(/\\/g,"/"),Z=I.replace(/\\/g,"/");return Y.replace(Z,".")}function W(Q){if(Array.isArray(Q)){let Y=0,Z=0;for(let J of Q){let{size:$,files:q}=W(J);Y+=$,Z+=q}return{size:Y,files:Z}}let V=0,H=0,I=Array.from(new Bun.Glob("**/*").scanSync({cwd:Q,absolute:!0}));for(let Y of I){let Z=Bun.file(Y);if(Z.size>0)V+=Z.size,H++}return{size:V,files:H}}import{fileURLToPath as n,pathToFileURL as i}from"url";import{isAbsolute as D,join as r,resolve as e}from"path";import{rm as t}from"fs/promises";import{builtinModules as z}from"module";import{mkdir as f,chmod as d}from"fs/promises";import{dirname as F,relative as L,join as M,basename as m,extname as p,resolve as k}from"path";import u from"unplugin-isolated-decl/esbuild";import U from"pretty-bytes";async function E(Q,V,H){let I=c(V.input,Q);if(V.stub){for(let[q,K]of Object.entries(I)){let X=M(Q.pkgDir,"dist",`${q}.mjs`);await f(F(X),{recursive:!0}),console.log(`[bundle] ${_(X)} (stub)`);let O=await Bun.file(K).text(),B=new Bun.Transpiler({loader:"ts"}).scan(O).exports.includes("default"),w=O.split(`
3
+ `)[0],N=w.startsWith("#!"),G=L(F(X),K);if(G=G.replace(/\\/g,"/"),await Bun.write(X,`${N?w+`
4
+ `:""}export * from "${G}";
5
+ ${B?`export { default } from "${G}";
6
+ `:""}`),N)await d(X,493);await Bun.write(X.replace(/\.mjs$/,".d.mts"),`export * from "${G}";
7
+ ${B?`export { default } from "${G}";
8
+ `:""}`)}return}let Y=[...z,...z.map((q)=>`node:${q}`),...[...Object.keys(Q.pkg.dependencies||{}),...Object.keys(Q.pkg.peerDependencies||{})].flatMap((q)=>[q])],Z={root:Q.pkgDir,entrypoints:Object.values(I),outdir:k(Q.pkgDir,V.outDir||"dist"),target:"bun",format:"esm",external:Y,minify:V.minify??!1,naming:{entry:"[name].mjs",chunk:"_chunks/[name].mjs"},splitting:!0,metafile:!0,plugins:V.dts!==!1?[u()]:[],...V.bun};await H.bunConfig?.(Z,Q);let J=await Bun.build(Z);if(!J.success){console.error("Build failed:");for(let q of J.logs)if(q.level==="error")console.error(` ${q.message}`);throw Error("Build failed")}await H.bunOutput?.(Z,Q);let $=[];for(let[q,K]of Object.entries(J.metafile.outputs)){if(!K.entryPoint)continue;if(q.endsWith(".ts"))continue;let X=q.replace(`${Z.outdir}${x("path").sep}`,""),O=K.exports||[],C=(K.imports||[]).filter((R)=>!R.path.startsWith(".")).map((R)=>R.path).sort();$.push({name:X,exports:O,deps:C,size:K.bytes,minSize:K.bytes,minGzipSize:K.bytes,sideEffectSize:K.bytes})}console.log(`
9
+ ${$.map((q)=>`[bundle] ${_(M(Z.outdir,q.name),Q.pkgDir)}
10
+ Size: ${U(q.size)}, ${U(q.minSize)} minified, ${U(q.minGzipSize)} min+gzipped (Side effects: ${U(q.sideEffectSize)})
11
+ ${q.exports.some((K)=>K!=="default")?`Exports: ${q.exports.join(", ")}
12
+ `:""}${q.deps.length>0?`Dependencies: ${q.deps.join(", ")}`:""}`).join(`
13
+
14
+ `)}`)}function c(Q,V){let H={};for(let I of Array.isArray(Q)?Q:[Q]){if(!I.startsWith("/"))I=k(V.pkgDir,I);let Y=L(M(V.pkgDir,"src"),I);if(Y.startsWith(".."))Y=L(M(V.pkgDir),I);if(Y.startsWith(".."))throw Error(`Source should be within the package directory (${V.pkgDir}): ${I}`);let Z=M(F(Y),m(Y,p(Y)));if(H[Z])throw Error(`Rename one of the entries to avoid a conflict in the dist name "${Z}":
15
+ - ${I}
16
+ - ${H[Z]}`);H[Z]=I}return H}import{mkdir as g,symlink as h,chmod as S}from"fs/promises";import{dirname as j,extname as y,join as T,relative as l}from"path";var{Glob:o}=globalThis.Bun;var v=/^#![^\n]*/;async function b(Q,V){let H=[],I=new o("**/*.*");for await(let $ of I.scan(V.input)){if(V.filter&&await V.filter($)===!1)continue;H.push((async()=>{let q=T(V.input,$);switch(y(q)){case".ts":{let X=T(V.outDir,$.replace(/\.ts$/,".mjs")),O=await s(q,V,X);if(await g(j(X),{recursive:!0}),await Bun.write(X,O),v.test(O))await S(X,493);return X}default:{let X=T(V.outDir,$);if(await g(j(X),{recursive:!0}),V.stub)await h(q,X,"junction").catch(()=>{});else{let O=await Bun.file(q).text();if(await Bun.write(X,O),v.test(O))await S(X,493)}return X}}})())}let Y=await Promise.allSettled(H),Z=Y.filter(($)=>$.status==="rejected").map(($)=>$.reason);if(Z.length>0){let $=[],q=[];for(let K of Z.flatMap((X)=>Array.isArray(X.cause)?X.cause:[X]))if(K.message?.includes("--isolatedDeclarations"))$.push(K);else q.push(K);for(let K of q)console.error(K);for(let K of $)console.warn(K);if(q.length>0)throw Error(`Errors while transforming ${V.input}`)}let J=Y.filter(($)=>$.status==="fulfilled").map(($)=>$.value);console.log(`
17
+ [transform] ${_(V.outDir+"/")}${V.stub?" (stub)":""}
18
+ ${a(J.map(($)=>_($)))}`)}function a(Q,V=process.stdout.columns||80){if(Q.length===0)return"";let I=Math.max(...Q.map((J)=>J.length))+2,Y=Math.max(1,Math.floor(V/I)),Z=[];for(let J=0;J<Q.length;J+=Y){let $=Q.slice(J,J+Y);Z.push($.map((q)=>q.padEnd(I)).join(""))}return Z.join(`
19
+ `)}async function s(Q,V,H){let I=await Bun.file(Q).text();if(V.stub){let q=new Bun.Transpiler({loader:"ts"}).scan(I).exports.includes("default"),K=l(j(H),Q);return K=K.replace(/\\/g,"/"),`export * from "${K}";${q?`
20
+ export { default } from "${K}";`:""}`}let Y={loader:V.transpiler?.loader||"ts",target:V.transpiler?.target||"bun",tsconfig:V.transpiler?.tsconfig};return new Bun.Transpiler(Y).transformSync(I)}import qq from"pretty-bytes";async function Bq(Q){let V=Date.now(),H=A(Q.cwd),Y={pkg:await Kq(r(H,"package.json")).catch(()=>({})),pkgDir:H};console.log(`Building \`${Y.pkg.name||"<no name>"}\` (\`${Y.pkgDir}\`)`);let Z=Q.hooks||{};await Z.start?.(Y);let J=(Q.entries||[]).map((q)=>{let K;if(typeof q==="string"){let[X,O]=q.split(":");K=X.endsWith("/")?{type:"transform",input:X,outDir:O}:{type:"bundle",input:X.split(","),outDir:O}}else K=q;if(!K.input)throw Error(`Build entry missing \`input\`: ${JSON.stringify(K,null,2)}`);return K={...K},K.outDir=A(K.outDir||"dist",H),K.input=Array.isArray(K.input)?K.input.map((X)=>A(X,H)):A(K.input,H),K});await Z.entries?.(J,Y);let $=[];for(let q of J.map((K)=>K.outDir).sort((K,X)=>(K??"").localeCompare(X??"")))if(!$.some((K)=>q.startsWith(K)))$.push(q);for(let q of $)console.log(`Cleaning up \`${_(q)}\``),await t(q,{recursive:!0,force:!0});for(let q of J)await(q.type==="bundle"?E(Y,q,Z):b(Y,q));if(await Z.end?.(Y),!J.every((q)=>q.stub)){let q=W($);console.log(`
21
+ \u03A3 Total dist byte size: ${qq(q.size)} (${q.files} files)`)}console.log(`
22
+ build finished in ${Date.now()-V}ms`)}function A(Q,V){return typeof Q==="string"&&D(Q)?Q:Q instanceof URL?n(Q):e(V||".",Q||".")}function Kq(Q){return import(D(Q)?i(Q).href:Q,{with:{type:"json"}}).then((H)=>H.default)}
23
+ export{_ as a,W as b,Bq as c};
@@ -0,0 +1,5 @@
1
+ import type { BuildConfig } from "./types";
2
+ /**
3
+ * Build dist/ from src/
4
+ */
5
+ export declare function build(config: BuildConfig): Promise<void>;
@@ -0,0 +1,3 @@
1
+ import type { BuildContext, BuildHooks, BundleEntry } from "../types";
2
+ export declare function bunBuild(ctx: BuildContext, entry: BundleEntry, hooks: BuildHooks): Promise<void>;
3
+ export declare function normalizeBundleInputs(input: string | string[], ctx: BuildContext): Record<string, string>;
@@ -0,0 +1,5 @@
1
+ import type { BuildContext, TransformEntry } from "../types";
2
+ /**
3
+ * Transform all .ts modules in a directory using Bun.Transpiler.
4
+ */
5
+ export declare function transformDir(ctx: BuildContext, entry: TransformEntry): Promise<void>;
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/dist/cli.mjs ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ import{c as d}from"./_chunks/index.mjs";import{defineCommand as u,runMain as l}from"citty";import{loadConfig as p}from"c12";var c=u({meta:{name:"build",version:"0.0.0",description:"Build your project with Bun"},args:{dir:{type:"string",description:"Project root directory",default:"."},stub:{type:"boolean",description:"Generate stub builds (re-export source files)",default:!1},entries:{type:"positional",description:"Build entries (e.g., src/index.ts or src/)",required:!1}},async run({args:i}){let{config:r={}}=await p({name:"build",configFile:"build.config",cwd:i.dir}),n=i.entries?Array.isArray(i.entries)?i.entries:[i.entries]:r.entries||[],o=n.map((e)=>{if(typeof e==="string"){let[t,s]=e.split(":");return t.endsWith("/")?{type:"transform",input:t,outDir:s}:{type:"bundle",input:t.split(","),outDir:s}}return e});if(i.stub)for(let e of o)e.stub=!0;if(n.length===0)console.error("No build entries specified."),process.exit(1);await d({cwd:i.dir,...r,entries:o})}});l(c);
@@ -0,0 +1,3 @@
1
+ export * from "./build";
2
+ export * from "./types";
3
+ export * from "./utils";
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ // @bun
2
+ import{a as g,b as j,c as k}from"./_chunks/index.mjs";export{g as fmtPath,k as build,j as analyzeDir};
@@ -0,0 +1,80 @@
1
+ import type { BuildConfig as BunBuildOptions, TranspilerOptions } from "bun";
2
+ export interface BuildContext {
3
+ pkgDir: string;
4
+ pkg: {
5
+ name: string;
6
+ } & Record<string, unknown>;
7
+ }
8
+ export type _BuildEntry = {
9
+ /**
10
+ * Output directory relative to project root.
11
+ *
12
+ * Defaults to `dist/` if not provided.
13
+ */
14
+ outDir?: string;
15
+ /**
16
+ * Avoid actual build but instead link to the source files.
17
+ */
18
+ stub?: boolean;
19
+ };
20
+ export type BundleEntry = _BuildEntry & {
21
+ type: "bundle";
22
+ /**
23
+ * Entry point(s) to bundle relative to the project root.
24
+ * */
25
+ input: string | string[];
26
+ /**
27
+ * Minify the output using Bun.
28
+ *
29
+ * Defaults to `false` if not provided.
30
+ */
31
+ minify?: boolean | {
32
+ whitespace?: boolean;
33
+ syntax?: boolean;
34
+ identifiers?: boolean;
35
+ };
36
+ /**
37
+ * Options passed to Bun.build.
38
+ *
39
+ * See [Bun.build options](https://bun.sh/docs/bundler) for more details.
40
+ */
41
+ bun?: Partial<BunBuildOptions>;
42
+ /**
43
+ * Declaration generation options.
44
+ *
45
+ * Set to `false` to disable.
46
+ */
47
+ dts?: boolean;
48
+ };
49
+ export type TransformEntry = _BuildEntry & {
50
+ type: "transform";
51
+ /**
52
+ * Directory to transform relative to the project root.
53
+ */
54
+ input: string;
55
+ /**
56
+ * Options passed to Bun.Transpiler.
57
+ */
58
+ transpiler?: Partial<TranspilerOptions>;
59
+ /**
60
+ * A filter function to exclude files from being transformed.
61
+ */
62
+ filter?: (filePath: string) => boolean | Promise<boolean>;
63
+ /**
64
+ * If sets to `false`, or if the function returns `false`, declaration files won't be emitted for the module.
65
+ */
66
+ dts?: boolean | ((filePath: string) => boolean | Promise<boolean>);
67
+ };
68
+ export type BuildEntry = BundleEntry | TransformEntry;
69
+ export interface BuildHooks {
70
+ start?: (ctx: BuildContext) => void | Promise<void>;
71
+ end?: (ctx: BuildContext) => void | Promise<void>;
72
+ entries?: (entries: BuildEntry[], ctx: BuildContext) => void | Promise<void>;
73
+ bunConfig?: (cfg: BunBuildOptions, ctx: BuildContext) => void | Promise<void>;
74
+ bunOutput?: (cfg: BunBuildOptions, ctx: BuildContext) => void | Promise<void>;
75
+ }
76
+ export interface BuildConfig {
77
+ cwd?: string | URL;
78
+ entries?: (BuildEntry | string)[];
79
+ hooks?: BuildHooks;
80
+ }
@@ -0,0 +1,5 @@
1
+ export declare function fmtPath(path: string, cwd?: string): string;
2
+ export declare function analyzeDir(dir: string | string[]): {
3
+ size: number;
4
+ files: number;
5
+ };
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@bunit/build",
3
+ "version": "0.0.0",
4
+ "description": "A blazing-fast build tool powered by Bun for TypeScript libraries with flexible bundling and transformation modes",
5
+ "keywords": [
6
+ "build",
7
+ "bun",
8
+ "bundle",
9
+ "bundler",
10
+ "library",
11
+ "package",
12
+ "tooling",
13
+ "transform",
14
+ "typescript"
15
+ ],
16
+ "homepage": "https://github.com/DemoMacro/BunIt#readme",
17
+ "bugs": {
18
+ "url": "https://github.com/DemoMacro/BunIt/issues"
19
+ },
20
+ "license": "MIT",
21
+ "author": {
22
+ "name": "Demo Macro",
23
+ "email": "abc@imst.xyz",
24
+ "url": "https://www.demomacro.com/"
25
+ },
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/DemoMacro/BunIt.git"
29
+ },
30
+ "bin": {
31
+ "built": "dist/cli.mjs"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "main": "dist/index.mjs",
37
+ "types": "dist/index.d.ts",
38
+ "exports": {
39
+ ".": {
40
+ "types": "./dist/index.d.ts",
41
+ "import": "./dist/index.mjs"
42
+ }
43
+ },
44
+ "scripts": {
45
+ "dev": "bun run src/cli.ts --stub",
46
+ "build": "bun run src/cli.ts",
47
+ "prepack": "bun run build"
48
+ },
49
+ "dependencies": {
50
+ "c12": "4.0.0-beta.3",
51
+ "citty": "0.2.1",
52
+ "pretty-bytes": "7.1.0",
53
+ "unplugin-isolated-decl": "0.15.7"
54
+ },
55
+ "devDependencies": {}
56
+ }