@orochibraru/svelte-smol 1.3.2 → 1.5.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 CHANGED
@@ -46,12 +46,37 @@ relative to its own path, so it can be run from any working directory:
46
46
  ./build/server
47
47
  ```
48
48
 
49
+ ### `compile: false`
50
+
51
+ `bun build --compile` bundles every dependency into the binary, and a native
52
+ (`.node`) addon like `sharp` or `better-sqlite3` can't be bundled that way. Set
53
+ `compile: false` to emit a plain bundle instead:
54
+
55
+ ```text
56
+ build/
57
+ ├── index.js # the server bundle, run with `bun`
58
+ ├── healthcheck # still a compiled binary
59
+ ├── client/
60
+ └── prerendered/
61
+ ```
62
+
63
+ Dependencies stay external, so ship `node_modules` next to `build/` (or anywhere
64
+ up the tree) and start it with:
65
+
66
+ ```bash
67
+ bun run ./build/index.js
68
+ ```
69
+
70
+ Everything else — env vars, the `healthcheck` binary, `serveAssets`,
71
+ instrumentation — works the same.
72
+
49
73
  ## Options
50
74
 
51
75
  ```js
52
76
  adapter({
53
77
  out: "build", // output directory
54
78
  name: "server", // executable filename within `out`
79
+ compile: true, // false → emit build/index.js (run with `bun`) instead of a binary
55
80
  target: undefined, // cross-compile target, e.g. "bun-linux-x64"
56
81
  bytecode: false, // embed a V8 bytecode cache (faster cold start, bigger binary)
57
82
  minify: false, // minify the bundled server code
package/index.ts CHANGED
@@ -9,10 +9,22 @@ export interface AdapterOptions {
9
9
  */
10
10
  out?: string;
11
11
  /**
12
- * Filename of the compiled executable, written into `out`.
12
+ * Filename of the compiled executable, written into `out`. Ignored when
13
+ * {@link AdapterOptions.compile | `compile`} is `false` (the server bundle
14
+ * is always `index.js` then).
13
15
  * @default "server"
14
16
  */
15
17
  name?: string;
18
+ /**
19
+ * Compile the server to a single standalone executable with
20
+ * `bun build --compile`. Turn this off to emit a plain `index.js` bundle
21
+ * instead, run with `bun run build/index.js` alongside a `node_modules`
22
+ * directory — the only way to ship a dependency with a native (`.node`)
23
+ * addon that `bun build --compile` can't embed (`sharp`, `sqlite3`, …).
24
+ * The `healthcheck` binary is still compiled either way.
25
+ * @default true
26
+ */
27
+ compile?: boolean;
16
28
  /**
17
29
  * Cross-compilation target for `bun build --compile`, e.g.
18
30
  * `"bun-linux-x64"`, `"bun-linux-arm64-musl"`, `"bun-darwin-arm64"`,
@@ -96,6 +108,10 @@ const templates = fileURLToPath(new URL("./templates", import.meta.url));
96
108
  * Bun runtime (`bun --bun vite build`, or a `bunfig.toml` with `[run] bun =
97
109
  * true`); loading the config alone works under Node too.
98
110
  *
111
+ * With {@link AdapterOptions.compile | `compile: false`} it emits a plain
112
+ * `build/index.js` bundle instead (dependencies external, run with `bun`),
113
+ * which is the only way to ship a native (`.node`) addon.
114
+ *
99
115
  * Output, all written to {@link AdapterOptions.out | `out`}:
100
116
  *
101
117
  * ```text
@@ -140,6 +156,7 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
140
156
  const {
141
157
  out = "build",
142
158
  name = "server",
159
+ compile = true,
143
160
  target,
144
161
  bytecode = false,
145
162
  minify = false,
@@ -209,6 +226,7 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
209
226
  serveAssets,
210
227
  precompress,
211
228
  healthcheck: healthcheckConfig,
229
+ compiled: compile,
212
230
  }),
213
231
  ENV: "./env.ts",
214
232
  ENV_PREFIX: JSON.stringify(envPrefix),
@@ -231,35 +249,68 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
231
249
  );
232
250
  }
233
251
 
234
- const compile = async (entrypoint: string, outName: string) => {
235
- builder.log.minor(
236
- target ? `Compiling ${outName} (${target})` : `Compiling ${outName}`,
237
- );
238
- const result = await Bun.build({
239
- entrypoints: [entrypoint],
240
- target: "bun",
241
- minify,
242
- bytecode,
243
- sourcemap: sourcemap ? "linked" : "none",
244
- compile: {
245
- outfile: `${out}/${outName}`,
246
- ...(target ? { target } : {}),
247
- },
248
- });
249
-
252
+ const check = (
253
+ result: Awaited<ReturnType<typeof Bun.build>>,
254
+ label: string,
255
+ ) => {
250
256
  if (!result.success) {
251
257
  for (const message of result.logs) {
252
258
  builder.log.error(String(message));
253
259
  }
254
- throw new Error(`\`bun build --compile\` failed for ${outName}`);
260
+ throw new Error(`\`bun build\` failed for ${label}`);
255
261
  }
262
+ };
256
263
 
264
+ const compileBinary = async (entrypoint: string, outName: string) => {
265
+ builder.log.minor(
266
+ target ? `Compiling ${outName} (${target})` : `Compiling ${outName}`,
267
+ );
268
+ check(
269
+ await Bun.build({
270
+ entrypoints: [entrypoint],
271
+ target: "bun",
272
+ minify,
273
+ bytecode,
274
+ sourcemap: sourcemap ? "linked" : "none",
275
+ compile: {
276
+ outfile: `${out}/${outName}`,
277
+ ...(target ? { target } : {}),
278
+ },
279
+ }),
280
+ outName,
281
+ );
257
282
  builder.log.success(`Compiled ${out}/${outName}`);
258
283
  };
259
284
 
260
- await compile(entry, name);
285
+ const bundleServer = async (entrypoint: string) => {
286
+ builder.log.minor("Bundling index.js");
287
+ // `packages: "external"` keeps every `node_modules` dependency out
288
+ // of the bundle so it resolves from disk at runtime — that is what
289
+ // lets native (`.node`) addons work, which is the whole point of
290
+ // skipping `--compile`. Ship `node_modules` next to `build/`.
291
+ check(
292
+ await Bun.build({
293
+ entrypoints: [entrypoint],
294
+ target: "bun",
295
+ format: "esm",
296
+ packages: "external",
297
+ minify,
298
+ sourcemap: sourcemap ? "linked" : "none",
299
+ outdir: out,
300
+ naming: "index.js",
301
+ }),
302
+ "index.js",
303
+ );
304
+ builder.log.success(`Bundled ${out}/index.js`);
305
+ };
306
+
307
+ if (compile) {
308
+ await compileBinary(entry, name);
309
+ } else {
310
+ await bundleServer(entry);
311
+ }
261
312
  if (healthcheckConfig) {
262
- await compile(`${tmp}/healthcheck.ts`, "healthcheck");
313
+ await compileBinary(`${tmp}/healthcheck.ts`, "healthcheck");
263
314
  }
264
315
  },
265
316
  };
package/internal.d.ts CHANGED
@@ -38,5 +38,6 @@ declare const BUILD_OPTIONS: {
38
38
  serveAssets: boolean;
39
39
  precompress: boolean;
40
40
  healthcheck: false | { path: string };
41
+ compiled: boolean;
41
42
  };
42
43
  declare const SERVE_OPTIONS: Record<string, unknown>;
package/package.json CHANGED
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "name": "@orochibraru/svelte-smol",
3
- "version": "1.3.2",
3
+ "version": "1.5.0",
4
4
  "type": "module",
5
5
  "main": "./index.ts",
6
+ "keywords": [
7
+ "bun",
8
+ "svelte",
9
+ "sveltekit",
10
+ "adapter",
11
+ "typescript"
12
+ ],
6
13
  "module": "./index.ts",
7
14
  "types": "./index.ts",
8
15
  "author": {
@@ -36,14 +43,12 @@
36
43
  },
37
44
  "devDependencies": {
38
45
  "@biomejs/biome": "^2.5.11",
39
- "@semantic-release/changelog": "^7.0.0",
40
- "@semantic-release/git": "^11.0.1",
41
46
  "@semantic-release/github": "^12.0.9",
42
47
  "@semantic-release/npm": "^13.1.5",
43
48
  "@sveltejs/kit": "^2.70.3",
44
49
  "@sveltejs/vite-plugin-svelte": "^7.3.0",
45
50
  "@types/bun": "^1.4.0",
46
- "conventional-changelog-conventionalcommits": "^10.4.0",
51
+ "conventional-changelog-conventionalcommits": "^8",
47
52
  "husky": "^9.1.7",
48
53
  "semantic-release": "^25.0.9",
49
54
  "svelte": "^5.56.10",
@@ -11,7 +11,7 @@ const server = new Server(manifest) as SvelteKitServer & {
11
11
  websocket?: () => Bun.WebSocketHandler<undefined> | undefined;
12
12
  };
13
13
 
14
- const { serveAssets, precompress, healthcheck } = BUILD_OPTIONS;
14
+ const { serveAssets, precompress, healthcheck, compiled } = BUILD_OPTIONS;
15
15
 
16
16
  const origin = env("ORIGIN", undefined);
17
17
  const xff_depth = Number.parseInt(env("XFF_DEPTH", "1"), 10);
@@ -20,14 +20,17 @@ const protocol_header = env("PROTOCOL_HEADER", "").toLowerCase();
20
20
  const host_header = env("HOST_HEADER", "").toLowerCase();
21
21
  const port_header = env("PORT_HEADER", "").toLowerCase();
22
22
 
23
- // Static assets and prerendered pages are deployed next to the executable:
24
- // <dir>/<binary>
23
+ // Static assets and prerendered pages are deployed next to the server:
24
+ // <dir>/<server>
25
25
  // <dir>/client/…
26
26
  // <dir>/prerendered/…
27
- // `ASSETS_DIR` overrides that parent directory (absolute, or relative to the
28
- // binary). `import.meta.dir` is a virtual path inside a compiled binary, so
29
- // the real on-disk location comes from `process.execPath`.
30
- const assets_root = resolve(dirname(process.execPath), env("ASSETS_DIR", ""));
27
+ // `ASSETS_DIR` overrides that parent directory (absolute, or relative to it).
28
+ // In a compiled binary `import.meta.dir` is a virtual path, so the real
29
+ // on-disk location comes from `process.execPath`; in a plain `index.js`
30
+ // bundle `process.execPath` is the `bun` binary, so `import.meta.dir` (the
31
+ // `build/` directory) is the one that's right.
32
+ const self_dir = compiled ? dirname(process.execPath) : import.meta.dir;
33
+ const assets_root = resolve(self_dir, env("ASSETS_DIR", ""));
31
34
  const client_dir = `${assets_root}/client${base}`;
32
35
  const prerendered_dir = `${assets_root}/prerendered${base}`;
33
36
  const immutable_prefix = `${base}/${manifest.appDir}/immutable/`;