@orochibraru/svelte-smol 1.4.0 → 1.5.1

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,40 @@ 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
+ ```bash
64
+ bun run ./build/index.js
65
+ ```
66
+
67
+ Pure-JS dependencies are still bundled into `index.js`. A native addon can't be,
68
+ so its `require` stays in the output and resolves from `node_modules` at runtime
69
+ (looked up from `index.js`'s own location, so the working directory doesn't
70
+ matter). Ship `node_modules` for those — a production install is enough, since
71
+ everything that got bundled needn't be there.
72
+
73
+ Everything else — env vars, the `healthcheck` binary, `serveAssets`,
74
+ instrumentation — works the same.
75
+
49
76
  ## Options
50
77
 
51
78
  ```js
52
79
  adapter({
53
80
  out: "build", // output directory
54
81
  name: "server", // executable filename within `out`
82
+ compile: true, // false → emit build/index.js (run with `bun`) instead of a binary
55
83
  target: undefined, // cross-compile target, e.g. "bun-linux-x64"
56
84
  bytecode: false, // embed a V8 bytecode cache (faster cold start, bigger binary)
57
85
  minify: false, // minify the bundled server code
package/index.ts CHANGED
@@ -9,10 +9,23 @@ 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 `build/index.js`
21
+ * bundle instead, run with `bun run build/index.js`. Pure-JS dependencies
22
+ * are still bundled in; a native (`.node`) addon can't be, so it resolves
23
+ * from `node_modules` at runtime — which a `bun` process can do and a
24
+ * compiled binary can't. This is the only way to ship `sharp`, `sqlite3`
25
+ * and the like. The `healthcheck` binary is still compiled either way.
26
+ * @default true
27
+ */
28
+ compile?: boolean;
16
29
  /**
17
30
  * Cross-compilation target for `bun build --compile`, e.g.
18
31
  * `"bun-linux-x64"`, `"bun-linux-arm64-musl"`, `"bun-darwin-arm64"`,
@@ -96,6 +109,10 @@ const templates = fileURLToPath(new URL("./templates", import.meta.url));
96
109
  * Bun runtime (`bun --bun vite build`, or a `bunfig.toml` with `[run] bun =
97
110
  * true`); loading the config alone works under Node too.
98
111
  *
112
+ * With {@link AdapterOptions.compile | `compile: false`} it emits a plain
113
+ * `build/index.js` bundle instead (run with `bun`), the only way to ship a
114
+ * native (`.node`) addon.
115
+ *
99
116
  * Output, all written to {@link AdapterOptions.out | `out`}:
100
117
  *
101
118
  * ```text
@@ -140,6 +157,7 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
140
157
  const {
141
158
  out = "build",
142
159
  name = "server",
160
+ compile = true,
143
161
  target,
144
162
  bytecode = false,
145
163
  minify = false,
@@ -209,6 +227,7 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
209
227
  serveAssets,
210
228
  precompress,
211
229
  healthcheck: healthcheckConfig,
230
+ compiled: compile,
212
231
  }),
213
232
  ENV: "./env.ts",
214
233
  ENV_PREFIX: JSON.stringify(envPrefix),
@@ -231,35 +250,69 @@ export default function adapter(options: AdapterOptions = {}): Adapter {
231
250
  );
232
251
  }
233
252
 
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
-
253
+ const check = (
254
+ result: Awaited<ReturnType<typeof Bun.build>>,
255
+ label: string,
256
+ ) => {
250
257
  if (!result.success) {
251
258
  for (const message of result.logs) {
252
259
  builder.log.error(String(message));
253
260
  }
254
- throw new Error(`\`bun build --compile\` failed for ${outName}`);
261
+ throw new Error(`\`bun build\` failed for ${label}`);
255
262
  }
263
+ };
256
264
 
265
+ const compileBinary = async (entrypoint: string, outName: string) => {
266
+ builder.log.minor(
267
+ target ? `Compiling ${outName} (${target})` : `Compiling ${outName}`,
268
+ );
269
+ check(
270
+ await Bun.build({
271
+ entrypoints: [entrypoint],
272
+ target: "bun",
273
+ minify,
274
+ bytecode,
275
+ sourcemap: sourcemap ? "linked" : "none",
276
+ compile: {
277
+ outfile: `${out}/${outName}`,
278
+ ...(target ? { target } : {}),
279
+ },
280
+ }),
281
+ outName,
282
+ );
257
283
  builder.log.success(`Compiled ${out}/${outName}`);
258
284
  };
259
285
 
260
- await compile(entry, name);
286
+ const bundleServer = async (entrypoint: string) => {
287
+ builder.log.minor("Bundling index.js");
288
+ // Same bundle as the compiled binary, just emitted as a file. Every
289
+ // pure-JS dependency is inlined; a native (`.node`) addon can't be,
290
+ // so its `require` stays in the output and resolves from
291
+ // `node_modules` at runtime — which is exactly what a plain `bun`
292
+ // process (unlike a compiled binary) can do. Ship `node_modules`
293
+ // for those; anything fully bundled needn't be installed.
294
+ check(
295
+ await Bun.build({
296
+ entrypoints: [entrypoint],
297
+ target: "bun",
298
+ format: "esm",
299
+ minify,
300
+ sourcemap: sourcemap ? "linked" : "none",
301
+ outdir: out,
302
+ naming: "index.js",
303
+ }),
304
+ "index.js",
305
+ );
306
+ builder.log.success(`Bundled ${out}/index.js`);
307
+ };
308
+
309
+ if (compile) {
310
+ await compileBinary(entry, name);
311
+ } else {
312
+ await bundleServer(entry);
313
+ }
261
314
  if (healthcheckConfig) {
262
- await compile(`${tmp}/healthcheck.ts`, "healthcheck");
315
+ await compileBinary(`${tmp}/healthcheck.ts`, "healthcheck");
263
316
  }
264
317
  },
265
318
  };
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,6 +1,6 @@
1
1
  {
2
2
  "name": "@orochibraru/svelte-smol",
3
- "version": "1.4.0",
3
+ "version": "1.5.1",
4
4
  "type": "module",
5
5
  "main": "./index.ts",
6
6
  "keywords": [
@@ -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/`;