bosia 0.9.10 → 1.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 +1 -1
- package/package.json +4 -1
- package/src/core/build.ts +46 -9
- package/src/core/dev.ts +2 -2
- package/src/core/html.ts +10 -4
- package/templates/default/package.json +3 -0
- package/templates/demo/package.json +3 -0
- package/templates/shop/package.json +3 -0
- package/templates/store/package.json +3 -0
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ bun run start
|
|
|
52
52
|
|
|
53
53
|
| Layer | Technology |
|
|
54
54
|
| ----------- | ------------------------------------------ |
|
|
55
|
-
| Runtime | [Bun](https://bun.sh)
|
|
55
|
+
| Runtime | [Bun](https://bun.sh) ≥ 1.4 |
|
|
56
56
|
| HTTP Server | Built-in (`Bun.serve`) |
|
|
57
57
|
| UI | [Svelte 5](https://svelte.dev) (Runes) |
|
|
58
58
|
| CSS | [Tailwind CSS v4](https://tailwindcss.com) |
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bosia",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"engines": {
|
|
6
|
+
"bun": ">=1.4"
|
|
7
|
+
},
|
|
5
8
|
"description": "A fast, batteries-included fullstack framework — SSR · Svelte 5 Runes · Bun. File-based routing. No Node.js, no Vite. Runs on Bun or Cloudflare Workers.",
|
|
6
9
|
"keywords": [
|
|
7
10
|
"bun",
|
package/src/core/build.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
writeFileSync,
|
|
3
|
+
readFileSync,
|
|
4
|
+
rmSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
unlinkSync,
|
|
9
|
+
rmdirSync,
|
|
10
|
+
} from "fs";
|
|
11
|
+
import { basename, join, relative, resolve } from "path";
|
|
3
12
|
import type { RouteManifest } from "./types.ts";
|
|
4
13
|
|
|
5
14
|
import { scanRoutes, RouteConflictError } from "./scanner.ts";
|
|
@@ -92,9 +101,39 @@ if (process.env.BOSIA_SKIP_ROUTE_SCAN === "1") {
|
|
|
92
101
|
// would clobber a concurrently-running `bosia dev` whose compiled server lives
|
|
93
102
|
// at .bosia/dev/ — the codegen files (routes*.ts, env.*.ts, types/) are the
|
|
94
103
|
// only things this build needs to clear to avoid stale entries on route renames.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
// Windows won't delete a file another process holds open (a running `bosia
|
|
105
|
+
// start`, an editor, antivirus scanning fresh files); warn instead of silently
|
|
106
|
+
// building over stale output. rmSync is only a first try: on Windows, Bun 1.4.2
|
|
107
|
+
// threw ENOENT for an existing "./dist" (and with `force` hid it, deleting
|
|
108
|
+
// nothing). So resolve the path, check what's left, and finish entry by entry —
|
|
109
|
+
// a real failure then names the exact file.
|
|
110
|
+
function clearOutput(path: string): void {
|
|
111
|
+
const abs = resolve(path);
|
|
112
|
+
if (!existsSync(abs)) return;
|
|
113
|
+
try {
|
|
114
|
+
rmSync(abs, { recursive: true, maxRetries: 5, retryDelay: 100 });
|
|
115
|
+
} catch {}
|
|
116
|
+
if (!existsSync(abs)) return;
|
|
117
|
+
try {
|
|
118
|
+
removeTree(abs);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
const e = err as NodeJS.ErrnoException;
|
|
121
|
+
console.warn(
|
|
122
|
+
`⚠️ Could not delete ${e.path ?? path} (${e.code ?? String(err)}) — stop whatever is using it and rebuild.`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function removeTree(path: string): void {
|
|
127
|
+
for (const entry of readdirSync(path, { withFileTypes: true })) {
|
|
128
|
+
const child = join(path, entry.name);
|
|
129
|
+
if (entry.isDirectory()) removeTree(child);
|
|
130
|
+
else unlinkSync(child);
|
|
131
|
+
}
|
|
132
|
+
rmdirSync(path);
|
|
133
|
+
}
|
|
134
|
+
clearOutput(OUT_DIR);
|
|
135
|
+
// A Bun build must not ship a leftover Workers bundle from an earlier target.
|
|
136
|
+
if (target !== "workers" && existsSync(`${OUT_DIR}/worker`)) clearOutput(`${OUT_DIR}/worker`);
|
|
98
137
|
for (const p of [
|
|
99
138
|
".bosia/routes.ts",
|
|
100
139
|
".bosia/routes.client.ts",
|
|
@@ -104,9 +143,7 @@ for (const p of [
|
|
|
104
143
|
".bosia/runtime.workers.ts",
|
|
105
144
|
".bosia/types",
|
|
106
145
|
]) {
|
|
107
|
-
|
|
108
|
-
rmSync(p, { recursive: true, force: true });
|
|
109
|
-
} catch {}
|
|
146
|
+
clearOutput(p);
|
|
110
147
|
}
|
|
111
148
|
|
|
112
149
|
// 1. Scan routes (or reuse the cached manifest — see 0b-pre)
|
|
@@ -287,7 +324,7 @@ for (const output of clientResult.outputs) {
|
|
|
287
324
|
const rel = toPosix(relative(`${OUT_DIR}/client`, output.path)); // URL path, not fs path
|
|
288
325
|
if (output.path.endsWith(".js")) jsFiles.push(rel);
|
|
289
326
|
if (output.path.endsWith(".css")) cssFiles.push(rel);
|
|
290
|
-
if (
|
|
327
|
+
if (output.kind === "entry-point" && output.path.endsWith(".js")) {
|
|
291
328
|
clientEntry = rel;
|
|
292
329
|
}
|
|
293
330
|
}
|
package/src/core/dev.ts
CHANGED
|
@@ -423,8 +423,8 @@ const devServer = Bun.serve({
|
|
|
423
423
|
// the eBPF cgroup filter only permits packets to/from 127.0.0.0/8 + ::1.
|
|
424
424
|
// "localhost" resolves to both ::1 and 127.0.0.1; bun's fetch() picks IPv6
|
|
425
425
|
// first, but the inner Bun.serve() listens IPv4-only, so the v6 connect
|
|
426
|
-
// fails fast and (under bun 1.3) doesn't fall back to v4. Pinning to
|
|
427
|
-
// avoids the failure path entirely.
|
|
426
|
+
// fails fast and (seen under bun 1.3) doesn't fall back to v4. Pinning to
|
|
427
|
+
// v4 avoids the failure path entirely, whatever bun's resolver does.
|
|
428
428
|
target.hostname = "127.0.0.1";
|
|
429
429
|
target.port = String(APP_PORT);
|
|
430
430
|
|
package/src/core/html.ts
CHANGED
|
@@ -38,6 +38,12 @@ const TW_CSS = `${B}/bosia-tw.css`;
|
|
|
38
38
|
const FAVICON = `${B}/favicon.svg`;
|
|
39
39
|
const SSE = `${B}/__bosia/sse`;
|
|
40
40
|
|
|
41
|
+
// The client entry, emitted verbatim — never with a `?v=` buster. Split chunks
|
|
42
|
+
// import it by bare relative URL (Bun 1.4 keeps shared code in the entry), so a
|
|
43
|
+
// query here makes the browser load it twice: two Svelte runtimes, and hydration
|
|
44
|
+
// dies with "reading 'call'". The content-hashed name is already the buster.
|
|
45
|
+
const ENTRY = `${DIST}/${distManifest.entry}`;
|
|
46
|
+
|
|
41
47
|
/**
|
|
42
48
|
* Handed to the client bundle so its router strips the same prefix the server
|
|
43
49
|
* added. Emitted before the module script, and omitted entirely at the origin
|
|
@@ -195,7 +201,7 @@ export function buildHtml(
|
|
|
195
201
|
: "";
|
|
196
202
|
|
|
197
203
|
const scripts = csr
|
|
198
|
-
? `${baseScript(nonce)}${envScript}${dataIslands}${sysScript}\n <script${n} type="module" src="${
|
|
204
|
+
? `${baseScript(nonce)}${envScript}${dataIslands}${sysScript}\n <script${n} type="module" src="${ENTRY}"></script>`
|
|
199
205
|
: isDev
|
|
200
206
|
? `\n <script${n}>!function r(){var e=new EventSource("${SSE}");e.addEventListener("reload",()=>location.reload());e.onopen=()=>r._ok||(r._ok=1);e.onerror=()=>{e.close();setTimeout(r,2000)}}()</script>`
|
|
201
207
|
: "";
|
|
@@ -264,7 +270,7 @@ export function buildHtmlShellOpen(
|
|
|
264
270
|
`\n ${faviconLine}${twCssLink()}\n` +
|
|
265
271
|
componentCssLinks() +
|
|
266
272
|
` <script${n}>${THEME_INIT_JS}</script>\n` +
|
|
267
|
-
` <link rel="modulepreload" href="${
|
|
273
|
+
` <link rel="modulepreload" href="${ENTRY}">`
|
|
268
274
|
);
|
|
269
275
|
}
|
|
270
276
|
|
|
@@ -276,7 +282,7 @@ export function buildHtmlShellOpen(
|
|
|
276
282
|
` ${twCssLink()}\n` +
|
|
277
283
|
componentCssLinks() +
|
|
278
284
|
` <script${n}>${THEME_INIT_JS}</script>\n` +
|
|
279
|
-
` <link rel="modulepreload" href="${
|
|
285
|
+
` <link rel="modulepreload" href="${ENTRY}">`
|
|
280
286
|
);
|
|
281
287
|
}
|
|
282
288
|
|
|
@@ -401,7 +407,7 @@ export function buildHtmlTail(
|
|
|
401
407
|
if (ssrFlag || depsInject) {
|
|
402
408
|
out += `\n<script${n}>${ssrFlag}${depsInject}</script>`;
|
|
403
409
|
}
|
|
404
|
-
out += `\n<script${n} type="module" src="${
|
|
410
|
+
out += `\n<script${n} type="module" src="${ENTRY}"></script>`;
|
|
405
411
|
} else if (isDev) {
|
|
406
412
|
out += `\n<script${n}>!function r(){var e=new EventSource("${SSE}");e.addEventListener("reload",()=>location.reload());e.onopen=()=>r._ok||(r._ok=1);e.onerror=()=>{e.close();setTimeout(r,2000)}}()</script>`;
|
|
407
413
|
}
|