This commit is contained in:
Benjamin Toby 2026-03-21 17:08:04 +01:00
parent d75125d9fa
commit 070e6860d8
7 changed files with 33 additions and 203 deletions

View File

@ -67,18 +67,41 @@ The goal is a framework that is:
## Installation
Install Bunext directly from GitHub:
### From the Moduletrace registry (recommended)
Configure the `@moduletrace` scope to point at the registry — pick one:
**`.npmrc`** (works with npm, bun, and most tools):
```ini
@moduletrace:registry=https://git.tben.me/api/packages/moduletrace/npm/
```
**`bunfig.toml`** (Bun-native):
```toml
[install.scopes]
"@moduletrace" = { registry = "https://git.tben.me/api/packages/moduletrace/npm/" }
```
Then install:
```bash
bun add @moduletrace/bunext
```
Or globally:
```bash
bun add -g @moduletrace/bunext
```
### From GitHub (alternative)
```bash
bun add github:moduletrace/bunext
```
Install globally:
```bash
bun add -g github:moduletrace/bunext
```
---
## Quick Start
@ -157,7 +180,7 @@ bun run start
**Global install** — install once and use `bunext` from anywhere:
```bash
bun add -g github:moduletrace/bunext
bun add -g @moduletrace/bunext
bunext dev
bunext build
bunext start

View File

@ -1,2 +0,0 @@
#!/usr/bin/env bun
export {};

131
dist/build/build.js vendored
View File

@ -1,131 +0,0 @@
#!/usr/bin/env bun
import plugin from "bun-plugin-tailwind";
import { existsSync } from "fs";
import { rm } from "fs/promises";
import path from "path";
if (process.argv.includes("--help") || process.argv.includes("-h")) {
console.log(`
🏗 Bun Build Script
Usage: bun run build.ts [options]
Common Options:
--outdir <path> Output directory (default: "dist")
--minify Enable minification (or --minify.whitespace, --minify.syntax, etc)
--sourcemap <type> Sourcemap type: none|linked|inline|external
--target <target> Build target: browser|bun|node
--format <format> Output format: esm|cjs|iife
--splitting Enable code splitting
--packages <type> Package handling: bundle|external
--public-path <path> Public path for assets
--env <mode> Environment handling: inline|disable|prefix*
--conditions <list> Package.json export conditions (comma separated)
--external <list> External packages (comma separated)
--banner <text> Add banner text to output
--footer <text> Add footer text to output
--define <obj> Define global constants (e.g. --define.VERSION=1.0.0)
--help, -h Show this help message
Example:
bun run build.ts --outdir=dist --minify --sourcemap=linked --external=react,react-dom
`);
process.exit(0);
}
const toCamelCase = (str) => str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
const parseValue = (value) => {
if (value === "true")
return true;
if (value === "false")
return false;
if (/^\d+$/.test(value))
return parseInt(value, 10);
if (/^\d*\.\d+$/.test(value))
return parseFloat(value);
if (value.includes(","))
return value.split(",").map((v) => v.trim());
return value;
};
function parseArgs() {
const config = {};
const args = process.argv.slice(2);
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (arg === undefined)
continue;
if (!arg.startsWith("--"))
continue;
if (arg.startsWith("--no-")) {
const key = toCamelCase(arg.slice(5));
config[key] = false;
continue;
}
if (!arg.includes("=") &&
(i === args.length - 1 || args[i + 1]?.startsWith("--"))) {
const key = toCamelCase(arg.slice(2));
config[key] = true;
continue;
}
let key;
let value;
if (arg.includes("=")) {
[key, value] = arg.slice(2).split("=", 2);
}
else {
key = arg.slice(2);
value = args[++i] ?? "";
}
key = toCamelCase(key);
if (key.includes(".")) {
const [parentKey, childKey] = key.split(".");
config[parentKey] = config[parentKey] || {};
config[parentKey][childKey] = parseValue(value);
}
else {
config[key] = parseValue(value);
}
}
return config;
}
const formatFileSize = (bytes) => {
const units = ["B", "KB", "MB", "GB"];
let size = bytes;
let unitIndex = 0;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
return `${size.toFixed(2)} ${units[unitIndex]}`;
};
console.log("\n🚀 Starting build process...\n");
const cliConfig = parseArgs();
const outdir = cliConfig.outdir || path.join(process.cwd(), "dist");
if (existsSync(outdir)) {
console.log(`🗑️ Cleaning previous build at ${outdir}`);
await rm(outdir, { recursive: true, force: true });
}
const start = performance.now();
const entrypoints = [...new Bun.Glob("**.html").scanSync("src/app")]
.map((a) => path.resolve("src/app", a))
.filter((dir) => !dir.includes("node_modules"));
console.log(`📄 Found ${entrypoints.length} HTML ${entrypoints.length === 1 ? "file" : "files"} to process\n`);
const result = await Bun.build({
entrypoints,
outdir,
plugins: [plugin],
minify: true,
target: "browser",
sourcemap: "linked",
define: {
"process.env.NODE_ENV": JSON.stringify("production"),
},
...cliConfig,
});
const end = performance.now();
const outputTable = result.outputs.map((output) => ({
File: path.relative(process.cwd(), output.path),
Type: output.kind,
Size: formatFileSize(output.size),
}));
console.table(outputTable);
const buildTime = (end - start).toFixed(2);
console.log(`\n✅ Build completed in ${buildTime}ms\n`);

View File

@ -1,5 +0,0 @@
type Params = {
req: Request;
};
export default function ({ req }: Params): Promise<Response>;
export {};

View File

@ -1,54 +0,0 @@
import grabDirNames from "../../utils/grab-dir-names";
import { AppData } from "../../data/app-data";
import path from "path";
import grabRootFile from "./web-pages/grab-root-file";
import grabPageBundledReactComponent from "./web-pages/grab-page-bundled-react-component";
import writeHMRTsxModule from "./web-pages/write-hmr-tsx-module";
const { BUNX_HYDRATION_SRC_DIR } = grabDirNames();
export default async function ({ req }) {
try {
const url = new URL(req.url);
const target_href = url.searchParams.get("href");
if (!target_href) {
return new Response(`No HREF passed to /${AppData["ClientHMRPath"]}`, { status: 404 });
}
const target_href_url = new URL(target_href);
const match = global.ROUTER.match(target_href_url.pathname);
if (!match?.filePath) {
return new Response(`No pages file matched for this path`, {
status: 404,
});
}
const out_file = path.join(BUNX_HYDRATION_SRC_DIR, target_href_url.pathname, "index.js");
const { root_file } = grabRootFile();
const { tsx } = (await grabPageBundledReactComponent({
file_path: match.filePath,
root_file,
})) || {};
if (!tsx) {
throw new Error(`Couldn't grab txt string`);
}
const artifact = await writeHMRTsxModule({
tsx,
out_file,
});
const file = Bun.file(out_file);
if (await file.exists()) {
return new Response(file, {
headers: {
"Content-Type": "text/javascript",
},
});
}
return new Response("Not found", {
status: 404,
});
}
catch (error) {
const error_msg = error.message;
console.error(error_msg);
return new Response(error_msg || "HMR Error", {
status: 404,
});
}
}

0
dist/index.js vendored Executable file → Normal file
View File

View File

@ -2,7 +2,7 @@
"name": "@moduletrace/bunext",
"module": "index.ts",
"type": "module",
"version": "1.0.7",
"version": "1.0.8",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
@ -28,7 +28,7 @@
"scripts": {
"dev": "tsc --watch",
"git:push": "tsc --noEmit && tsc && git add . && git commit -m 'Update bundler. Handle non-existent file error.' && git push",
"compile": "bun build ./src/commands/index.ts --compile --outfile bin/bunext",
"compile": "bun build ./src/commands/index.ts --compile --outfile bin/bunext --minify",
"build": "tsc",
"test": "bun test --max-concurrency=1"
},
@ -54,7 +54,6 @@
"registry": "https://npm.pkg.github.com"
},
"dependencies": {
"@moduletrace/bunext": "github:moduletrace/bunext",
"@tailwindcss/postcss": "^4.2.2",
"bun-plugin-tailwind": "^0.1.2",
"chalk": "^5.6.2",