bosbun 0.0.5 → 0.0.7
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 +12 -12
- package/package.json +5 -5
- package/src/cli/add.ts +5 -5
- package/src/cli/create.ts +67 -7
- package/src/cli/feat.ts +5 -5
- package/src/cli/index.ts +18 -17
- package/src/cli/start.ts +2 -4
- package/src/core/build.ts +17 -17
- package/src/core/client/App.svelte +12 -12
- package/src/core/client/hydrate.ts +7 -7
- package/src/core/client/prefetch.ts +8 -8
- package/src/core/client/router.svelte.ts +1 -1
- package/src/core/dev.ts +8 -7
- package/src/core/env.ts +1 -1
- package/src/core/envCodegen.ts +20 -20
- package/src/core/hooks.ts +2 -2
- package/src/core/html.ts +20 -20
- package/src/core/paths.ts +41 -0
- package/src/core/plugin.ts +48 -14
- package/src/core/prerender.ts +3 -2
- package/src/core/renderer.ts +3 -3
- package/src/core/routeFile.ts +6 -6
- package/src/core/routeTypes.ts +10 -10
- package/src/core/server.ts +4 -4
- package/src/core/types.ts +1 -1
- package/src/lib/index.ts +3 -3
- package/templates/default/.env.example +6 -6
- package/templates/default/README.md +3 -3
- package/templates/default/package.json +4 -4
- package/templates/default/public/favicon.svg +14 -0
- package/templates/default/src/routes/+page.svelte +4 -4
- package/templates/default/tsconfig.json +1 -1
- package/templates/demo/.env.example +52 -0
- package/templates/demo/README.md +23 -0
- package/templates/demo/package.json +20 -0
- package/templates/demo/public/.gitkeep +0 -0
- package/templates/demo/public/favicon.svg +14 -0
- package/templates/demo/src/app.css +132 -0
- package/templates/demo/src/app.d.ts +7 -0
- package/templates/demo/src/hooks.server.ts +21 -0
- package/templates/demo/src/lib/utils.ts +1 -0
- package/templates/demo/src/routes/(public)/+layout.svelte +31 -0
- package/templates/demo/src/routes/(public)/+page.svelte +79 -0
- package/templates/demo/src/routes/(public)/about/+page.server.ts +1 -0
- package/templates/demo/src/routes/(public)/about/+page.svelte +31 -0
- package/templates/demo/src/routes/(public)/all/[...catchall]/+page.svelte +38 -0
- package/templates/demo/src/routes/(public)/blog/+page.svelte +55 -0
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.server.ts +62 -0
- package/templates/demo/src/routes/(public)/blog/[slug]/+page.svelte +53 -0
- package/templates/demo/src/routes/+error.svelte +15 -0
- package/templates/demo/src/routes/+layout.server.ts +10 -0
- package/templates/demo/src/routes/+layout.svelte +6 -0
- package/templates/demo/src/routes/actions-test/+page.server.ts +28 -0
- package/templates/demo/src/routes/actions-test/+page.svelte +60 -0
- package/templates/demo/src/routes/api/hello/+server.ts +44 -0
- package/templates/demo/tsconfig.json +22 -0
package/README.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# bosbun
|
|
2
2
|
|
|
3
|
-
The `
|
|
3
|
+
The `bosbun` package — framework core + CLI.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
bun add
|
|
8
|
+
bun add bosbun
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Or scaffold a new project:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
|
|
14
|
+
bun x bosbun create my-app
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
## CLI
|
|
18
18
|
|
|
19
19
|
```
|
|
20
|
-
|
|
20
|
+
bosbun <command>
|
|
21
21
|
|
|
22
22
|
Commands:
|
|
23
|
-
create <name> Scaffold a new
|
|
23
|
+
create <name> Scaffold a new Bosbun project
|
|
24
24
|
dev Start the development server (port 3000)
|
|
25
25
|
build Build for production
|
|
26
26
|
start Run the production server
|
|
@@ -64,7 +64,7 @@ src/routes/
|
|
|
64
64
|
|
|
65
65
|
```typescript
|
|
66
66
|
// src/routes/blog/[slug]/+page.server.ts
|
|
67
|
-
import type { LoadEvent } from "
|
|
67
|
+
import type { LoadEvent } from "bosbun";
|
|
68
68
|
|
|
69
69
|
export async function load({ params, url, locals, fetch, parent }: LoadEvent) {
|
|
70
70
|
const parentData = await parent(); // data from layout loaders above
|
|
@@ -89,7 +89,7 @@ Export named HTTP verb functions from `+server.ts`:
|
|
|
89
89
|
|
|
90
90
|
```typescript
|
|
91
91
|
// src/routes/api/items/+server.ts
|
|
92
|
-
import type { RequestEvent } from "
|
|
92
|
+
import type { RequestEvent } from "bosbun";
|
|
93
93
|
|
|
94
94
|
export function GET({ params, url, locals }: RequestEvent) {
|
|
95
95
|
return Response.json({ items: [] });
|
|
@@ -106,8 +106,8 @@ export async function POST({ request }: RequestEvent) {
|
|
|
106
106
|
Create `src/hooks.server.ts` to intercept every request:
|
|
107
107
|
|
|
108
108
|
```typescript
|
|
109
|
-
import { sequence } from "
|
|
110
|
-
import type { Handle } from "
|
|
109
|
+
import { sequence } from "bosbun";
|
|
110
|
+
import type { Handle } from "bosbun";
|
|
111
111
|
|
|
112
112
|
const authHandle: Handle = async ({ event, resolve }) => {
|
|
113
113
|
event.locals.user = await getUser(event.request);
|
|
@@ -128,8 +128,8 @@ export const handle = sequence(authHandle, loggingHandle);
|
|
|
128
128
|
## Public API
|
|
129
129
|
|
|
130
130
|
```typescript
|
|
131
|
-
import { cn, sequence } from "
|
|
132
|
-
import type { RequestEvent, LoadEvent, Handle } from "
|
|
131
|
+
import { cn, sequence } from "bosbun";
|
|
132
|
+
import type { RequestEvent, LoadEvent, Handle } from "bosbun";
|
|
133
133
|
```
|
|
134
134
|
|
|
135
135
|
| Export | Description |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bosbun",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A minimalist fullstack framework — SSR + Svelte 5 Runes + Bun + ElysiaJS",
|
|
6
6
|
"keywords": [
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
"name": "Jekibus",
|
|
17
17
|
"url": "https://bosapi.com"
|
|
18
18
|
},
|
|
19
|
-
"homepage": "https://github.com/bosapi/
|
|
19
|
+
"homepage": "https://github.com/bosapi/bosbun#readme",
|
|
20
20
|
"repository": {
|
|
21
21
|
"type": "git",
|
|
22
|
-
"url": "git+https://github.com/bosapi/
|
|
22
|
+
"url": "git+https://github.com/bosapi/bosbun.git"
|
|
23
23
|
},
|
|
24
24
|
"bugs": {
|
|
25
|
-
"url": "https://github.com/bosapi/
|
|
25
|
+
"url": "https://github.com/bosapi/bosbun/issues"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
28
|
"src",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
".": "./src/lib/index.ts"
|
|
35
35
|
},
|
|
36
36
|
"bin": {
|
|
37
|
-
"
|
|
37
|
+
"bosbun": "src/cli/index.ts"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"check": "tsc --noEmit"
|
package/src/cli/add.ts
CHANGED
|
@@ -2,16 +2,16 @@ import { join, dirname } from "path";
|
|
|
2
2
|
import { mkdirSync, writeFileSync } from "fs";
|
|
3
3
|
import { spawn } from "bun";
|
|
4
4
|
|
|
5
|
-
// ───
|
|
5
|
+
// ─── bosbun add <component> ────────────────────────────────
|
|
6
6
|
// Fetches a component from the GitHub registry and copies it
|
|
7
7
|
// into the user's src/lib/components/ui/<name>/ directory.
|
|
8
8
|
|
|
9
|
-
const REGISTRY_BASE = "https://raw.githubusercontent.com/bosapi/
|
|
9
|
+
const REGISTRY_BASE = "https://raw.githubusercontent.com/bosapi/bosbun/main/registry";
|
|
10
10
|
|
|
11
11
|
interface ComponentMeta {
|
|
12
12
|
name: string;
|
|
13
13
|
description: string;
|
|
14
|
-
dependencies: string[]; // other
|
|
14
|
+
dependencies: string[]; // other bosbun components required
|
|
15
15
|
files: string[];
|
|
16
16
|
npmDeps: Record<string, string>;
|
|
17
17
|
}
|
|
@@ -21,7 +21,7 @@ const installed = new Set<string>();
|
|
|
21
21
|
|
|
22
22
|
export async function runAdd(name: string | undefined) {
|
|
23
23
|
if (!name) {
|
|
24
|
-
console.error("❌ Please provide a component name.\n Usage:
|
|
24
|
+
console.error("❌ Please provide a component name.\n Usage: bosbun add <component>");
|
|
25
25
|
process.exit(1);
|
|
26
26
|
}
|
|
27
27
|
await addComponent(name, true);
|
|
@@ -31,7 +31,7 @@ export async function addComponent(name: string, root = false) {
|
|
|
31
31
|
if (installed.has(name)) return;
|
|
32
32
|
installed.add(name);
|
|
33
33
|
|
|
34
|
-
console.log(root ?
|
|
34
|
+
console.log(root ? `⬡ Installing component: ${name}\n` : ` 📦 Dependency: ${name}`);
|
|
35
35
|
|
|
36
36
|
const meta = await fetchJSON<ComponentMeta>(`${REGISTRY_BASE}/components/${name}/meta.json`);
|
|
37
37
|
|
package/src/cli/create.ts
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { resolve, join, basename } from "path";
|
|
2
2
|
import { existsSync, mkdirSync, readdirSync, statSync, readFileSync, writeFileSync } from "fs";
|
|
3
3
|
import { spawn } from "bun";
|
|
4
|
+
import * as readline from "readline";
|
|
4
5
|
|
|
5
|
-
// ───
|
|
6
|
+
// ─── bosbun create <name> [--template <name>] ──────────────
|
|
6
7
|
|
|
7
|
-
const
|
|
8
|
+
const TEMPLATES_DIR = resolve(import.meta.dir, "../../templates");
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
const TEMPLATE_DESCRIPTIONS: Record<string, string> = {
|
|
11
|
+
default: "Minimal starter with routing and Tailwind",
|
|
12
|
+
demo: "Full-featured demo with hooks, API routes, form actions, and more",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export async function runCreate(name: string | undefined, args: string[] = []) {
|
|
10
16
|
if (!name) {
|
|
11
|
-
console.error("❌ Please provide a project name.\n Usage:
|
|
17
|
+
console.error("❌ Please provide a project name.\n Usage: bosbun create my-app");
|
|
12
18
|
process.exit(1);
|
|
13
19
|
}
|
|
14
20
|
|
|
@@ -19,9 +25,29 @@ export async function runCreate(name: string | undefined) {
|
|
|
19
25
|
process.exit(1);
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
// Parse --template flag
|
|
29
|
+
let template: string | undefined;
|
|
30
|
+
const templateIdx = args.indexOf("--template");
|
|
31
|
+
if (templateIdx !== -1 && args[templateIdx + 1]) {
|
|
32
|
+
template = args[templateIdx + 1];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// If no --template flag, prompt interactively
|
|
36
|
+
if (!template) {
|
|
37
|
+
template = await promptTemplate();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Validate template exists
|
|
41
|
+
const templateDir = resolve(TEMPLATES_DIR, template);
|
|
42
|
+
if (!existsSync(templateDir)) {
|
|
43
|
+
const available = getAvailableTemplates().join(", ");
|
|
44
|
+
console.error(`❌ Unknown template: "${template}"\n Available: ${available}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log(`\n⬡ Creating Bosbun project: ${basename(targetDir)} (template: ${template})\n`);
|
|
23
49
|
|
|
24
|
-
copyDir(
|
|
50
|
+
copyDir(templateDir, targetDir, name);
|
|
25
51
|
|
|
26
52
|
console.log(`✅ Project created at ${targetDir}\n`);
|
|
27
53
|
|
|
@@ -35,10 +61,44 @@ export async function runCreate(name: string | undefined) {
|
|
|
35
61
|
if (exitCode !== 0) {
|
|
36
62
|
console.warn("⚠️ bun install failed — run it manually.");
|
|
37
63
|
} else {
|
|
38
|
-
console.log(`\n🎉 Ready!\n\n cd ${name}\n bun x
|
|
64
|
+
console.log(`\n🎉 Ready!\n\n cd ${name}\n bun x bosbun dev\n`);
|
|
39
65
|
}
|
|
40
66
|
}
|
|
41
67
|
|
|
68
|
+
function getAvailableTemplates(): string[] {
|
|
69
|
+
return readdirSync(TEMPLATES_DIR, { withFileTypes: true })
|
|
70
|
+
.filter((d) => d.isDirectory())
|
|
71
|
+
.map((d) => d.name)
|
|
72
|
+
.sort((a, b) => (a === "default" ? -1 : b === "default" ? 1 : a.localeCompare(b)));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async function promptTemplate(): Promise<string> {
|
|
76
|
+
const templates = getAvailableTemplates();
|
|
77
|
+
|
|
78
|
+
if (templates.length === 1) return templates[0];
|
|
79
|
+
|
|
80
|
+
console.log("\n? Which template?\n");
|
|
81
|
+
templates.forEach((t, i) => {
|
|
82
|
+
const desc = TEMPLATE_DESCRIPTIONS[t] ?? "";
|
|
83
|
+
const marker = i === 0 ? "❯" : " ";
|
|
84
|
+
console.log(` ${marker} ${t}${desc ? ` — ${desc}` : ""}`);
|
|
85
|
+
});
|
|
86
|
+
console.log();
|
|
87
|
+
|
|
88
|
+
const rl = readline.createInterface({
|
|
89
|
+
input: process.stdin,
|
|
90
|
+
output: process.stdout,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return new Promise<string>((resolvePromise) => {
|
|
94
|
+
rl.question(` Template name (default): `, (answer) => {
|
|
95
|
+
rl.close();
|
|
96
|
+
const trimmed = answer.trim();
|
|
97
|
+
resolvePromise(trimmed || "default");
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
42
102
|
function copyDir(src: string, dest: string, projectName: string) {
|
|
43
103
|
mkdirSync(dest, { recursive: true });
|
|
44
104
|
for (const entry of readdirSync(src, { withFileTypes: true })) {
|
package/src/cli/feat.ts
CHANGED
|
@@ -3,16 +3,16 @@ import { mkdirSync, writeFileSync } from "fs";
|
|
|
3
3
|
import { spawn } from "bun";
|
|
4
4
|
import { addComponent } from "./add.ts";
|
|
5
5
|
|
|
6
|
-
// ───
|
|
6
|
+
// ─── bosbun feat <feature> ─────────────────────────────────
|
|
7
7
|
// Fetches a feature scaffold from the GitHub registry.
|
|
8
8
|
// Installs required components, copies route/lib files, installs npm deps.
|
|
9
9
|
|
|
10
|
-
const REGISTRY_BASE = "https://raw.githubusercontent.com/bosapi/
|
|
10
|
+
const REGISTRY_BASE = "https://raw.githubusercontent.com/bosapi/bosbun/main/registry";
|
|
11
11
|
|
|
12
12
|
interface FeatureMeta {
|
|
13
13
|
name: string;
|
|
14
14
|
description: string;
|
|
15
|
-
components: string[]; //
|
|
15
|
+
components: string[]; // bosbun components to install via `bosbun add`
|
|
16
16
|
files: string[]; // source filenames in the registry feature dir
|
|
17
17
|
targets: string[]; // destination paths relative to project root
|
|
18
18
|
npmDeps: Record<string, string>;
|
|
@@ -20,11 +20,11 @@ interface FeatureMeta {
|
|
|
20
20
|
|
|
21
21
|
export async function runFeat(name: string | undefined) {
|
|
22
22
|
if (!name) {
|
|
23
|
-
console.error("❌ Please provide a feature name.\n Usage:
|
|
23
|
+
console.error("❌ Please provide a feature name.\n Usage: bosbun feat <feature>");
|
|
24
24
|
process.exit(1);
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
console.log(
|
|
27
|
+
console.log(`⬡ Installing feature: ${name}\n`);
|
|
28
28
|
|
|
29
29
|
const meta = await fetchJSON<FeatureMeta>(`${REGISTRY_BASE}/features/${name}/meta.json`);
|
|
30
30
|
|
package/src/cli/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
// ───
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
//
|
|
2
|
+
// ─── Bosbun CLI ────────────────────────────────────────────
|
|
3
|
+
// bosbun create <name> scaffold a new project
|
|
4
|
+
// bosbun dev start the development server
|
|
5
|
+
// bosbun build build for production
|
|
6
|
+
// bosbun start run the production server
|
|
7
|
+
// bosbun add <name> add a UI component from the registry
|
|
8
|
+
// bosbun feat <name> add a feature scaffold from the registry
|
|
9
9
|
|
|
10
10
|
const [, , command, ...args] = process.argv;
|
|
11
11
|
|
|
@@ -13,7 +13,7 @@ async function main() {
|
|
|
13
13
|
switch (command) {
|
|
14
14
|
case "create": {
|
|
15
15
|
const { runCreate } = await import("./create.ts");
|
|
16
|
-
await runCreate(args[0]);
|
|
16
|
+
await runCreate(args[0], args.slice(1));
|
|
17
17
|
break;
|
|
18
18
|
}
|
|
19
19
|
case "dev": {
|
|
@@ -43,13 +43,13 @@ async function main() {
|
|
|
43
43
|
}
|
|
44
44
|
default: {
|
|
45
45
|
console.log(`
|
|
46
|
-
|
|
46
|
+
⬡ Bosbun
|
|
47
47
|
|
|
48
48
|
Usage:
|
|
49
|
-
|
|
49
|
+
bosbun <command> [options]
|
|
50
50
|
|
|
51
51
|
Commands:
|
|
52
|
-
create <name>
|
|
52
|
+
create <name> [--template <t>] Scaffold a new Bosbun project
|
|
53
53
|
dev Start the development server
|
|
54
54
|
build Build for production
|
|
55
55
|
start Run the production server
|
|
@@ -57,12 +57,13 @@ Commands:
|
|
|
57
57
|
feat <feature> Add a feature scaffold from the registry
|
|
58
58
|
|
|
59
59
|
Examples:
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
bosbun create my-app
|
|
61
|
+
bosbun create my-app --template demo
|
|
62
|
+
bosbun dev
|
|
63
|
+
bosbun build
|
|
64
|
+
bosbun start
|
|
65
|
+
bosbun add button
|
|
66
|
+
bosbun feat login
|
|
66
67
|
`);
|
|
67
68
|
break;
|
|
68
69
|
}
|
package/src/cli/start.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { spawn } from "bun";
|
|
2
|
-
import { join } from "path";
|
|
3
2
|
import { loadEnv } from "../core/env.ts";
|
|
4
|
-
|
|
5
|
-
const BUNIA_NODE_MODULES = join(import.meta.dir, "..", "..", "node_modules");
|
|
3
|
+
import { BOSBUN_NODE_PATH } from "../core/paths.ts";
|
|
6
4
|
|
|
7
5
|
export async function runStart() {
|
|
8
6
|
loadEnv("production");
|
|
@@ -20,7 +18,7 @@ export async function runStart() {
|
|
|
20
18
|
env: {
|
|
21
19
|
...process.env,
|
|
22
20
|
NODE_ENV: "production",
|
|
23
|
-
NODE_PATH:
|
|
21
|
+
NODE_PATH: BOSBUN_NODE_PATH,
|
|
24
22
|
},
|
|
25
23
|
});
|
|
26
24
|
|
package/src/core/build.ts
CHANGED
|
@@ -6,29 +6,29 @@ import { spawnSync } from "bun";
|
|
|
6
6
|
import { scanRoutes } from "./scanner.ts";
|
|
7
7
|
import { generateRoutesFile } from "./routeFile.ts";
|
|
8
8
|
import { generateRouteTypes, ensureRootDirs } from "./routeTypes.ts";
|
|
9
|
-
import {
|
|
9
|
+
import { makeBosbunPlugin } from "./plugin.ts";
|
|
10
10
|
import { prerenderStaticRoutes } from "./prerender.ts";
|
|
11
11
|
import { loadEnv, classifyEnvVars } from "./env.ts";
|
|
12
12
|
import { generateEnvModules } from "./envCodegen.ts";
|
|
13
|
+
import { BOSBUN_NODE_PATH, resolveBosbunBin } from "./paths.ts";
|
|
13
14
|
|
|
14
|
-
// Resolved from this file's location inside the
|
|
15
|
+
// Resolved from this file's location inside the bosbun package
|
|
15
16
|
const CORE_DIR = import.meta.dir;
|
|
16
|
-
const BUNIA_NODE_MODULES = join(CORE_DIR, "..", "..", "node_modules");
|
|
17
17
|
|
|
18
18
|
// ─── Entry Point ─────────────────────────────────────────
|
|
19
19
|
|
|
20
20
|
const isProduction = process.env.NODE_ENV === "production";
|
|
21
21
|
|
|
22
|
-
console.log("🏗️ Starting
|
|
22
|
+
console.log("🏗️ Starting Bosbun build...\n");
|
|
23
23
|
|
|
24
|
-
// 0. Load .env files (before cleaning .
|
|
24
|
+
// 0. Load .env files (before cleaning .bosbun so loadEnv can set process.env early)
|
|
25
25
|
const envMode = isProduction ? "production" : "development";
|
|
26
26
|
const envVars = loadEnv(envMode);
|
|
27
27
|
const classifiedEnv = classifyEnvVars(envVars);
|
|
28
28
|
|
|
29
29
|
// 0b. Clean all generated output first
|
|
30
30
|
try { rmSync("./dist", { recursive: true, force: true }); } catch { }
|
|
31
|
-
try { rmSync("./.
|
|
31
|
+
try { rmSync("./.bosbun", { recursive: true, force: true }); } catch { }
|
|
32
32
|
|
|
33
33
|
// 1. Scan routes
|
|
34
34
|
const manifest = scanRoutes();
|
|
@@ -43,37 +43,37 @@ if (manifest.apis.length > 0) {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// 2. Generate .
|
|
46
|
+
// 2. Generate .bosbun/routes.ts (single file replaces all old code generators)
|
|
47
47
|
generateRoutesFile(manifest);
|
|
48
48
|
|
|
49
|
-
// 2b. Generate .
|
|
49
|
+
// 2b. Generate .bosbun/types/src/routes/**/$types.d.ts for IDE type inference
|
|
50
50
|
generateRouteTypes(manifest);
|
|
51
51
|
|
|
52
|
-
// 2c. Ensure tsconfig.json has rootDirs pointing at .
|
|
52
|
+
// 2c. Ensure tsconfig.json has rootDirs pointing at .bosbun/types
|
|
53
53
|
ensureRootDirs();
|
|
54
54
|
|
|
55
|
-
// 2d. Generate .
|
|
55
|
+
// 2d. Generate .bosbun/env.server.ts, .bosbun/env.client.ts, .bosbun/types/env.d.ts
|
|
56
56
|
generateEnvModules(classifiedEnv);
|
|
57
57
|
|
|
58
58
|
// 3. Build Tailwind CSS
|
|
59
59
|
console.log("\n🎨 Building Tailwind CSS...");
|
|
60
|
-
const tailwindBin =
|
|
60
|
+
const tailwindBin = resolveBosbunBin("tailwindcss");
|
|
61
61
|
const tailwindResult = spawnSync(
|
|
62
|
-
[tailwindBin, "-i", "./src/app.css", "-o", "./public/
|
|
62
|
+
[tailwindBin, "-i", "./src/app.css", "-o", "./public/bosbun-tw.css", ...(isProduction ? ["--minify"] : [])],
|
|
63
63
|
{
|
|
64
64
|
cwd: process.cwd(),
|
|
65
|
-
env: { ...process.env, NODE_PATH:
|
|
65
|
+
env: { ...process.env, NODE_PATH: BOSBUN_NODE_PATH },
|
|
66
66
|
},
|
|
67
67
|
);
|
|
68
68
|
if (tailwindResult.exitCode !== 0) {
|
|
69
69
|
console.error("❌ Tailwind CSS build failed:\n" + tailwindResult.stderr.toString());
|
|
70
70
|
process.exit(1);
|
|
71
71
|
}
|
|
72
|
-
console.log("✅ Tailwind CSS built: public/
|
|
72
|
+
console.log("✅ Tailwind CSS built: public/bosbun-tw.css");
|
|
73
73
|
|
|
74
|
-
// Separate plugin instances per build target (
|
|
75
|
-
const clientPlugin =
|
|
76
|
-
const serverPlugin =
|
|
74
|
+
// Separate plugin instances per build target (bosbun:env resolves differently)
|
|
75
|
+
const clientPlugin = makeBosbunPlugin("browser");
|
|
76
|
+
const serverPlugin = makeBosbunPlugin("bun");
|
|
77
77
|
|
|
78
78
|
// Build-time defines: inline PUBLIC_STATIC_* and STATIC_* vars
|
|
79
79
|
const staticDefines: Record<string, string> = {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { router } from "./router.svelte.ts";
|
|
3
3
|
import { findMatch } from "../matcher.ts";
|
|
4
|
-
import { clientRoutes } from "
|
|
4
|
+
import { clientRoutes } from "bosbun:routes";
|
|
5
5
|
import { consumePrefetch, prefetchCache } from "./prefetch.ts";
|
|
6
6
|
|
|
7
7
|
let {
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
const dataFetch = cached
|
|
59
59
|
? Promise.resolve(cached)
|
|
60
60
|
: match.route.hasServerData
|
|
61
|
-
? fetch(`/
|
|
61
|
+
? fetch(`/__bosbun/data?path=${encodeURIComponent(path)}`).then(r => r.json()).catch(() => null)
|
|
62
62
|
: Promise.resolve(null);
|
|
63
63
|
|
|
64
64
|
Promise.all([
|
|
@@ -95,9 +95,9 @@
|
|
|
95
95
|
-->
|
|
96
96
|
|
|
97
97
|
{#if navigating}
|
|
98
|
-
<div class="
|
|
98
|
+
<div class="bosbun-bar loading"></div>
|
|
99
99
|
{:else if navDone}
|
|
100
|
-
<div class="
|
|
100
|
+
<div class="bosbun-bar done"></div>
|
|
101
101
|
{/if}
|
|
102
102
|
|
|
103
103
|
{#if layoutComponents.length > 0}
|
|
@@ -128,28 +128,28 @@
|
|
|
128
128
|
{/snippet}
|
|
129
129
|
|
|
130
130
|
<style>
|
|
131
|
-
.
|
|
131
|
+
.bosbun-bar {
|
|
132
132
|
position: fixed;
|
|
133
133
|
top: 0;
|
|
134
134
|
left: 0;
|
|
135
135
|
height: 2px;
|
|
136
136
|
width: 100%;
|
|
137
|
-
background: var(--
|
|
137
|
+
background: var(--bosbun-loading-color, #f73b27);
|
|
138
138
|
z-index: 9999;
|
|
139
139
|
pointer-events: none;
|
|
140
140
|
transform-origin: left center;
|
|
141
141
|
}
|
|
142
|
-
.
|
|
143
|
-
animation:
|
|
142
|
+
.bosbun-bar.loading {
|
|
143
|
+
animation: bosbun-load 8s cubic-bezier(0.02, 0.5, 0.5, 1) forwards;
|
|
144
144
|
}
|
|
145
|
-
.
|
|
146
|
-
animation:
|
|
145
|
+
.bosbun-bar.done {
|
|
146
|
+
animation: bosbun-done 0.35s ease forwards;
|
|
147
147
|
}
|
|
148
|
-
@keyframes
|
|
148
|
+
@keyframes bosbun-load {
|
|
149
149
|
from { transform: scaleX(0); }
|
|
150
150
|
to { transform: scaleX(0.85); }
|
|
151
151
|
}
|
|
152
|
-
@keyframes
|
|
152
|
+
@keyframes bosbun-done {
|
|
153
153
|
from { transform: scaleX(1); opacity: 1; }
|
|
154
154
|
to { transform: scaleX(1); opacity: 0; }
|
|
155
155
|
}
|
|
@@ -3,7 +3,7 @@ import App from "./App.svelte";
|
|
|
3
3
|
import { router } from "./router.svelte.ts";
|
|
4
4
|
import { initPrefetch } from "./prefetch.ts";
|
|
5
5
|
import { findMatch } from "../matcher.ts";
|
|
6
|
-
import { clientRoutes } from "
|
|
6
|
+
import { clientRoutes } from "bosbun:routes";
|
|
7
7
|
|
|
8
8
|
// ─── Hydration ────────────────────────────────────────────
|
|
9
9
|
|
|
@@ -37,9 +37,9 @@ async function main() {
|
|
|
37
37
|
ssrMode: false,
|
|
38
38
|
ssrPageComponent,
|
|
39
39
|
ssrLayoutComponents,
|
|
40
|
-
ssrPageData: (window as any).
|
|
41
|
-
ssrLayoutData: (window as any).
|
|
42
|
-
ssrFormData: (window as any).
|
|
40
|
+
ssrPageData: (window as any).__BOSBUN_PAGE_DATA__ ?? {},
|
|
41
|
+
ssrLayoutData: (window as any).__BOSBUN_LAYOUT_DATA__ ?? [],
|
|
42
|
+
ssrFormData: (window as any).__BOSBUN_FORM_DATA__ ?? null,
|
|
43
43
|
},
|
|
44
44
|
});
|
|
45
45
|
}
|
|
@@ -53,10 +53,10 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
53
53
|
let retryDelay = 1000;
|
|
54
54
|
|
|
55
55
|
function connectSSE() {
|
|
56
|
-
const es = new EventSource("/
|
|
56
|
+
const es = new EventSource("/__bosbun/sse");
|
|
57
57
|
|
|
58
58
|
es.addEventListener("reload", () => {
|
|
59
|
-
console.log("[
|
|
59
|
+
console.log("[Bosbun] Reloading...");
|
|
60
60
|
window.location.reload();
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -71,7 +71,7 @@ if (process.env.NODE_ENV !== "production") {
|
|
|
71
71
|
|
|
72
72
|
es.onerror = () => {
|
|
73
73
|
es.close();
|
|
74
|
-
console.log(`[
|
|
74
|
+
console.log(`[Bosbun] SSE disconnected. Retrying in ${retryDelay / 1000}s...`);
|
|
75
75
|
setTimeout(connectSSE, retryDelay);
|
|
76
76
|
retryDelay = Math.min(retryDelay + 1000, 5000);
|
|
77
77
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ─── Link Prefetching ─────────────────────────────────────
|
|
2
|
-
// Supports `data-
|
|
2
|
+
// Supports `data-bosbun-preload="hover"` and `data-bosbun-preload="viewport"`
|
|
3
3
|
// on <a> elements or their ancestors.
|
|
4
4
|
|
|
5
5
|
export const prefetchCache = new Map<string, any>();
|
|
@@ -22,7 +22,7 @@ export async function prefetchPath(path: string): Promise<void> {
|
|
|
22
22
|
|
|
23
23
|
pending.add(path);
|
|
24
24
|
try {
|
|
25
|
-
const res = await fetch(`/
|
|
25
|
+
const res = await fetch(`/__bosbun/data?path=${encodeURIComponent(path)}`);
|
|
26
26
|
if (res.ok) {
|
|
27
27
|
prefetchCache.set(path, await res.json());
|
|
28
28
|
}
|
|
@@ -52,7 +52,7 @@ function observeViewportLinks(container: Element | Document = document) {
|
|
|
52
52
|
}, { rootMargin: "0px" });
|
|
53
53
|
|
|
54
54
|
const links = (container === document ? document : container as Element)
|
|
55
|
-
.querySelectorAll<HTMLAnchorElement>("a[data-
|
|
55
|
+
.querySelectorAll<HTMLAnchorElement>("a[data-bosbun-preload='viewport']");
|
|
56
56
|
|
|
57
57
|
for (const link of links) {
|
|
58
58
|
observer.observe(link);
|
|
@@ -67,9 +67,9 @@ export function initPrefetch(): void {
|
|
|
67
67
|
|
|
68
68
|
document.addEventListener("mouseover", (e) => {
|
|
69
69
|
if (!(e.target instanceof Element)) return;
|
|
70
|
-
// Early exit: skip if no [data-
|
|
71
|
-
const preloadEl = e.target.closest("[data-
|
|
72
|
-
if (!preloadEl || preloadEl.getAttribute("data-
|
|
70
|
+
// Early exit: skip if no [data-bosbun-preload="hover"] ancestor exists
|
|
71
|
+
const preloadEl = e.target.closest("[data-bosbun-preload]");
|
|
72
|
+
if (!preloadEl || preloadEl.getAttribute("data-bosbun-preload") !== "hover") return;
|
|
73
73
|
const anchor = e.target.closest("a") as HTMLAnchorElement | null;
|
|
74
74
|
if (!anchor) return;
|
|
75
75
|
const href = getLinkHref(anchor);
|
|
@@ -92,12 +92,12 @@ export function initPrefetch(): void {
|
|
|
92
92
|
for (const node of record.addedNodes) {
|
|
93
93
|
if (!(node instanceof Element)) continue;
|
|
94
94
|
// The node itself might be a viewport link
|
|
95
|
-
if (node.matches("a[data-
|
|
95
|
+
if (node.matches("a[data-bosbun-preload='viewport']")) {
|
|
96
96
|
observer.observe(node as HTMLAnchorElement);
|
|
97
97
|
}
|
|
98
98
|
// Or it might contain viewport links
|
|
99
99
|
for (const link of node.querySelectorAll<HTMLAnchorElement>(
|
|
100
|
-
"a[data-
|
|
100
|
+
"a[data-bosbun-preload='viewport']"
|
|
101
101
|
)) {
|
|
102
102
|
observer.observe(link);
|
|
103
103
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Singleton used by App.svelte and hydrate.ts.
|
|
4
4
|
|
|
5
5
|
import { findMatch } from "../matcher.ts";
|
|
6
|
-
import { clientRoutes } from "
|
|
6
|
+
import { clientRoutes } from "bosbun:routes";
|
|
7
7
|
|
|
8
8
|
export const router = new class Router {
|
|
9
9
|
currentRoute = $state(typeof window !== "undefined" ? window.location.pathname : "/");
|