@orochibraru/svelte-smol 1.5.2 → 1.6.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/dist/index.d.ts +149 -0
- package/dist/index.js +181 -0
- package/package.json +11 -8
- package/index.ts +0 -319
- package/internal.d.ts +0 -43
- /package/{templates → dist/templates}/env.ts +0 -0
- /package/{templates → dist/templates}/handler.ts +0 -0
- /package/{templates → dist/templates}/healthcheck.ts +0 -0
- /package/{templates → dist/templates}/index.ts +0 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { Adapter } from "@sveltejs/kit";
|
|
2
|
+
export interface AdapterOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Output directory. Holds the compiled executable plus the `client/` and
|
|
5
|
+
* `prerendered/` folders it serves.
|
|
6
|
+
* @default "build"
|
|
7
|
+
*/
|
|
8
|
+
out?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Filename of the compiled executable, written into `out`. Ignored when
|
|
11
|
+
* {@link AdapterOptions.compile | `compile`} is `false` (the server bundle
|
|
12
|
+
* is always `index.js` then).
|
|
13
|
+
* @default "server"
|
|
14
|
+
*/
|
|
15
|
+
name?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Compile the server to a single standalone executable with
|
|
18
|
+
* `bun build --compile`. Turn this off to emit a plain `build/index.js`
|
|
19
|
+
* bundle instead, run with `bun run build/index.js`. Pure-JS dependencies
|
|
20
|
+
* are still bundled in; a native (`.node`) addon can't be, so it resolves
|
|
21
|
+
* from `node_modules` at runtime — which a `bun` process can do and a
|
|
22
|
+
* compiled binary can't. This is the only way to ship `sharp`, `sqlite3`
|
|
23
|
+
* and the like. The `healthcheck` binary is still compiled either way.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
compile?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Cross-compilation target for `bun build --compile`, e.g.
|
|
29
|
+
* `"bun-linux-x64"`, `"bun-linux-arm64-musl"`, `"bun-darwin-arm64"`,
|
|
30
|
+
* `"bun-windows-x64"` (optional `-modern` / `-baseline` SIMD suffix, and
|
|
31
|
+
* `-musl` for Alpine). Bun downloads the matching runtime on first use.
|
|
32
|
+
* @default the host platform
|
|
33
|
+
*/
|
|
34
|
+
target?: Bun.Build.CompileTarget;
|
|
35
|
+
/**
|
|
36
|
+
* Emit a V8 bytecode cache into the executable for faster cold starts, at
|
|
37
|
+
* the cost of a larger binary.
|
|
38
|
+
* @default false
|
|
39
|
+
*/
|
|
40
|
+
bytecode?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Minify the bundled server code before embedding it.
|
|
43
|
+
* @default false
|
|
44
|
+
*/
|
|
45
|
+
minify?: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Embed a source map so server stack traces point at original code.
|
|
48
|
+
* @default false
|
|
49
|
+
*/
|
|
50
|
+
sourcemap?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Pre-compress client assets and prerendered pages to `.gz` / `.br`
|
|
53
|
+
* siblings. The handler serves them with the matching `Content-Encoding`
|
|
54
|
+
* when the request's `Accept-Encoding` allows.
|
|
55
|
+
* @default false
|
|
56
|
+
*/
|
|
57
|
+
precompress?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Compile a second tiny executable, `healthcheck`, alongside the server
|
|
60
|
+
* and expose a matching `GET` endpoint. The binary probes that endpoint
|
|
61
|
+
* over loopback (or the Unix socket) and exits `0` when healthy, `1`
|
|
62
|
+
* otherwise — ready to drop into a Docker `HEALTHCHECK`. Pass an object
|
|
63
|
+
* to change the endpoint path.
|
|
64
|
+
* @default true
|
|
65
|
+
*/
|
|
66
|
+
healthcheck?: boolean | {
|
|
67
|
+
path?: string;
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* Prefix for this adapter's own runtime env vars (`PORT`, `HOST`,
|
|
71
|
+
* `ORIGIN`, ...).
|
|
72
|
+
* @default ""
|
|
73
|
+
*/
|
|
74
|
+
envPrefix?: string;
|
|
75
|
+
/**
|
|
76
|
+
* Serve the app's static assets and prerendered pages from the
|
|
77
|
+
* executable. The `client/` and `prerendered/` folders must sit next to
|
|
78
|
+
* the binary (or point `ASSETS_DIR` at their parent). Turn off when a
|
|
79
|
+
* reverse proxy or CDN serves them instead.
|
|
80
|
+
* @default true
|
|
81
|
+
*/
|
|
82
|
+
serveAssets?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Extra options merged into the `Bun.serve()` call (`tls`, `reusePort`,
|
|
85
|
+
* `maxConnections`, a custom `error` handler, ...). Applied *before* this
|
|
86
|
+
* adapter's own required fields (`idleTimeout`, `maxRequestBodySize`,
|
|
87
|
+
* `fetch`, `hostname`/`port`/`unix`, `websocket`), so it can't be used to
|
|
88
|
+
* override request handling, only to add to it. Use the existing env vars
|
|
89
|
+
* (`IDLE_TIMEOUT`, `BODY_SIZE_LIMIT`, `HOST`/`PORT`, `SOCKET_PATH`,
|
|
90
|
+
* `SHUTDOWN_TIMEOUT`) to change those instead.
|
|
91
|
+
* @default {}
|
|
92
|
+
*/
|
|
93
|
+
serveOptions?: Record<string, unknown>;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* SvelteKit adapter that compiles the app into a single standalone executable
|
|
97
|
+
* with `bun build --compile`.
|
|
98
|
+
*
|
|
99
|
+
* `adapt()` writes the SvelteKit server and this package's entrypoint templates
|
|
100
|
+
* into a temp directory, then compiles them — `@sveltejs/kit` and every other
|
|
101
|
+
* pure-JS dependency bundled in — into one binary. The build must run under the
|
|
102
|
+
* Bun runtime (`bun --bun vite build`, or a `bunfig.toml` with `[run] bun =
|
|
103
|
+
* true`); loading the config alone works under Node too.
|
|
104
|
+
*
|
|
105
|
+
* With {@link AdapterOptions.compile | `compile: false`} it emits a plain
|
|
106
|
+
* `build/index.js` bundle instead (run with `bun`), the only way to ship a
|
|
107
|
+
* native (`.node`) addon.
|
|
108
|
+
*
|
|
109
|
+
* Output, all written to {@link AdapterOptions.out | `out`}:
|
|
110
|
+
*
|
|
111
|
+
* ```text
|
|
112
|
+
* build/
|
|
113
|
+
* ├── server the executable (rename with `name`)
|
|
114
|
+
* ├── client/ static assets, served by the executable
|
|
115
|
+
* └── prerendered/ prerendered pages, served by the executable
|
|
116
|
+
* ```
|
|
117
|
+
*
|
|
118
|
+
* The executable resolves `client/` and `prerendered/` from its own location
|
|
119
|
+
* (`dirname(process.execPath)`, overridable with the `ASSETS_DIR` env var), so
|
|
120
|
+
* it can run from any working directory. Deploy the whole `out` directory, or
|
|
121
|
+
* just the binary when {@link AdapterOptions.serveAssets | `serveAssets`} is
|
|
122
|
+
* off and a proxy/CDN serves the assets.
|
|
123
|
+
*
|
|
124
|
+
* Runtime configuration (`HOST`, `PORT`, `ORIGIN`, `BODY_SIZE_LIMIT`, …) is
|
|
125
|
+
* read from environment variables, optionally namespaced by
|
|
126
|
+
* {@link AdapterOptions.envPrefix | `envPrefix`}.
|
|
127
|
+
*
|
|
128
|
+
* @param options - see {@link AdapterOptions}
|
|
129
|
+
* @returns the configured SvelteKit {@link Adapter}
|
|
130
|
+
*
|
|
131
|
+
* @example
|
|
132
|
+
* ```js
|
|
133
|
+
* // svelte.config.js
|
|
134
|
+
* import adapter from "@orochibraru/svelte-smol";
|
|
135
|
+
*
|
|
136
|
+
* export default {
|
|
137
|
+
* kit: {
|
|
138
|
+
* adapter: adapter({
|
|
139
|
+
* // cross-compile for an Alpine container from any host
|
|
140
|
+
* target: "bun-linux-x64-musl",
|
|
141
|
+
* bytecode: true,
|
|
142
|
+
* }),
|
|
143
|
+
* },
|
|
144
|
+
* };
|
|
145
|
+
* ```
|
|
146
|
+
*
|
|
147
|
+
* @see {@link https://bun.com/docs/bundler/executables | Bun — Single-file executables}
|
|
148
|
+
*/
|
|
149
|
+
export default function adapter(options?: AdapterOptions): Adapter;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
// `node:url`, not `Bun.fileURLToPath`: this module is loaded at config-parse
|
|
3
|
+
// time by Node-based tooling too (svelte-check, the Svelte language server,
|
|
4
|
+
// `svelte-kit sync`), where `Bun` is undefined. Everything that actually needs
|
|
5
|
+
// the Bun runtime lives inside `adapt()`.
|
|
6
|
+
const templates = fileURLToPath(new URL("./templates", import.meta.url));
|
|
7
|
+
/**
|
|
8
|
+
* SvelteKit adapter that compiles the app into a single standalone executable
|
|
9
|
+
* with `bun build --compile`.
|
|
10
|
+
*
|
|
11
|
+
* `adapt()` writes the SvelteKit server and this package's entrypoint templates
|
|
12
|
+
* into a temp directory, then compiles them — `@sveltejs/kit` and every other
|
|
13
|
+
* pure-JS dependency bundled in — into one binary. The build must run under the
|
|
14
|
+
* Bun runtime (`bun --bun vite build`, or a `bunfig.toml` with `[run] bun =
|
|
15
|
+
* true`); loading the config alone works under Node too.
|
|
16
|
+
*
|
|
17
|
+
* With {@link AdapterOptions.compile | `compile: false`} it emits a plain
|
|
18
|
+
* `build/index.js` bundle instead (run with `bun`), the only way to ship a
|
|
19
|
+
* native (`.node`) addon.
|
|
20
|
+
*
|
|
21
|
+
* Output, all written to {@link AdapterOptions.out | `out`}:
|
|
22
|
+
*
|
|
23
|
+
* ```text
|
|
24
|
+
* build/
|
|
25
|
+
* ├── server the executable (rename with `name`)
|
|
26
|
+
* ├── client/ static assets, served by the executable
|
|
27
|
+
* └── prerendered/ prerendered pages, served by the executable
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* The executable resolves `client/` and `prerendered/` from its own location
|
|
31
|
+
* (`dirname(process.execPath)`, overridable with the `ASSETS_DIR` env var), so
|
|
32
|
+
* it can run from any working directory. Deploy the whole `out` directory, or
|
|
33
|
+
* just the binary when {@link AdapterOptions.serveAssets | `serveAssets`} is
|
|
34
|
+
* off and a proxy/CDN serves the assets.
|
|
35
|
+
*
|
|
36
|
+
* Runtime configuration (`HOST`, `PORT`, `ORIGIN`, `BODY_SIZE_LIMIT`, …) is
|
|
37
|
+
* read from environment variables, optionally namespaced by
|
|
38
|
+
* {@link AdapterOptions.envPrefix | `envPrefix`}.
|
|
39
|
+
*
|
|
40
|
+
* @param options - see {@link AdapterOptions}
|
|
41
|
+
* @returns the configured SvelteKit {@link Adapter}
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```js
|
|
45
|
+
* // svelte.config.js
|
|
46
|
+
* import adapter from "@orochibraru/svelte-smol";
|
|
47
|
+
*
|
|
48
|
+
* export default {
|
|
49
|
+
* kit: {
|
|
50
|
+
* adapter: adapter({
|
|
51
|
+
* // cross-compile for an Alpine container from any host
|
|
52
|
+
* target: "bun-linux-x64-musl",
|
|
53
|
+
* bytecode: true,
|
|
54
|
+
* }),
|
|
55
|
+
* },
|
|
56
|
+
* };
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @see {@link https://bun.com/docs/bundler/executables | Bun — Single-file executables}
|
|
60
|
+
*/
|
|
61
|
+
export default function adapter(options = {}) {
|
|
62
|
+
const { out = "build", name = "server", compile = true, target, bytecode = false, minify = false, sourcemap = false, precompress = false, healthcheck = true, envPrefix = "", serveAssets = true, serveOptions = {}, } = options;
|
|
63
|
+
const healthcheckConfig = healthcheck === false
|
|
64
|
+
? false
|
|
65
|
+
: {
|
|
66
|
+
path: (healthcheck === true ? undefined : healthcheck.path) ?? "/_health",
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
name: "@orochibraru/svelte-smol",
|
|
70
|
+
supports: {
|
|
71
|
+
instrumentation: () => true,
|
|
72
|
+
read: () => true,
|
|
73
|
+
},
|
|
74
|
+
async adapt(builder) {
|
|
75
|
+
const { base } = builder.config.kit.paths;
|
|
76
|
+
const tmp = builder.getBuildDirectory("adapter-bun");
|
|
77
|
+
builder.rimraf(out);
|
|
78
|
+
builder.rimraf(tmp);
|
|
79
|
+
builder.mkdirp(`${out}/`);
|
|
80
|
+
builder.mkdirp(tmp);
|
|
81
|
+
builder.log.minor("Copying assets");
|
|
82
|
+
builder.writeClient(`${out}/client${base}`);
|
|
83
|
+
builder.writePrerendered(`${out}/prerendered${base}`);
|
|
84
|
+
if (precompress) {
|
|
85
|
+
builder.log.minor("Compressing assets");
|
|
86
|
+
await Promise.all([
|
|
87
|
+
builder.compress(`${out}/client`),
|
|
88
|
+
builder.compress(`${out}/prerendered`),
|
|
89
|
+
]);
|
|
90
|
+
}
|
|
91
|
+
builder.log.minor("Building server");
|
|
92
|
+
builder.writeServer(`${tmp}/server`);
|
|
93
|
+
await Bun.write(`${tmp}/server/manifest.js`, [
|
|
94
|
+
`export const manifest = ${builder.generateManifest({ relativePath: "./" })};`,
|
|
95
|
+
`export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});`,
|
|
96
|
+
`export const base = ${JSON.stringify(base)};`,
|
|
97
|
+
].join("\n\n"));
|
|
98
|
+
// Entry templates ship as raw `.ts` — `bun build --compile` runs them
|
|
99
|
+
// straight through. The virtual specifiers (`ENV`, `MANIFEST`,
|
|
100
|
+
// `SERVER`, `HANDLER`) and the `ENV_PREFIX` / `BUILD_OPTIONS` /
|
|
101
|
+
// `SERVE_OPTIONS` tokens are resolved by this raw word-boundary token
|
|
102
|
+
// swap over the copied source.
|
|
103
|
+
builder.log.minor("Copying entrypoint");
|
|
104
|
+
builder.copy(templates, tmp, {
|
|
105
|
+
replace: {
|
|
106
|
+
BUILD_OPTIONS: JSON.stringify({
|
|
107
|
+
serveAssets,
|
|
108
|
+
precompress,
|
|
109
|
+
healthcheck: healthcheckConfig,
|
|
110
|
+
compiled: compile,
|
|
111
|
+
}),
|
|
112
|
+
ENV: "./env.ts",
|
|
113
|
+
ENV_PREFIX: JSON.stringify(envPrefix),
|
|
114
|
+
HANDLER: "./handler.ts",
|
|
115
|
+
MANIFEST: "./server/manifest.js",
|
|
116
|
+
SERVE_OPTIONS: JSON.stringify(serveOptions),
|
|
117
|
+
SERVER: "./server/index.js",
|
|
118
|
+
},
|
|
119
|
+
});
|
|
120
|
+
const entry = `${tmp}/index.ts`;
|
|
121
|
+
if (builder.hasServerInstrumentationFile?.()) {
|
|
122
|
+
// Instrumentation (OpenTelemetry &c.) has to load before anything
|
|
123
|
+
// else in the bundle. A compiled binary has no post-build
|
|
124
|
+
// entrypoint to rewrite, so prepend the import to the compile
|
|
125
|
+
// entrypoint instead.
|
|
126
|
+
await Bun.write(entry, `import "./server/instrumentation.server.js";\n${await Bun.file(entry).text()}`);
|
|
127
|
+
}
|
|
128
|
+
const check = (result, label) => {
|
|
129
|
+
if (!result.success) {
|
|
130
|
+
for (const message of result.logs) {
|
|
131
|
+
builder.log.error(String(message));
|
|
132
|
+
}
|
|
133
|
+
throw new Error(`\`bun build\` failed for ${label}`);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const compileBinary = async (entrypoint, outName) => {
|
|
137
|
+
builder.log.minor(target ? `Compiling ${outName} (${target})` : `Compiling ${outName}`);
|
|
138
|
+
check(await Bun.build({
|
|
139
|
+
entrypoints: [entrypoint],
|
|
140
|
+
target: "bun",
|
|
141
|
+
minify,
|
|
142
|
+
bytecode,
|
|
143
|
+
sourcemap: sourcemap ? "linked" : "none",
|
|
144
|
+
compile: {
|
|
145
|
+
outfile: `${out}/${outName}`,
|
|
146
|
+
...(target ? { target } : {}),
|
|
147
|
+
},
|
|
148
|
+
}), outName);
|
|
149
|
+
builder.log.success(`Compiled ${out}/${outName}`);
|
|
150
|
+
};
|
|
151
|
+
const bundleServer = async (entrypoint) => {
|
|
152
|
+
builder.log.minor("Bundling index.js");
|
|
153
|
+
// Same bundle as the compiled binary, just emitted as a file. Every
|
|
154
|
+
// pure-JS dependency is inlined; a native (`.node`) addon can't be,
|
|
155
|
+
// so its `require` stays in the output and resolves from
|
|
156
|
+
// `node_modules` at runtime — which is exactly what a plain `bun`
|
|
157
|
+
// process (unlike a compiled binary) can do. Ship `node_modules`
|
|
158
|
+
// for those; anything fully bundled needn't be installed.
|
|
159
|
+
check(await Bun.build({
|
|
160
|
+
entrypoints: [entrypoint],
|
|
161
|
+
target: "bun",
|
|
162
|
+
format: "esm",
|
|
163
|
+
minify,
|
|
164
|
+
sourcemap: sourcemap ? "linked" : "none",
|
|
165
|
+
outdir: out,
|
|
166
|
+
naming: "index.js",
|
|
167
|
+
}), "index.js");
|
|
168
|
+
builder.log.success(`Bundled ${out}/index.js`);
|
|
169
|
+
};
|
|
170
|
+
if (compile) {
|
|
171
|
+
await compileBinary(entry, name);
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
await bundleServer(entry);
|
|
175
|
+
}
|
|
176
|
+
if (healthcheckConfig) {
|
|
177
|
+
await compileBinary(`${tmp}/healthcheck.ts`, "healthcheck");
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@orochibraru/svelte-smol",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"main": "./index.
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"bun",
|
|
8
8
|
"svelte",
|
|
@@ -10,19 +10,20 @@
|
|
|
10
10
|
"adapter",
|
|
11
11
|
"typescript"
|
|
12
12
|
],
|
|
13
|
-
"module": "./index.
|
|
14
|
-
"types": "./index.ts",
|
|
13
|
+
"module": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
15
|
"author": {
|
|
16
16
|
"email": "orochibraru@gmail.com",
|
|
17
17
|
"name": "orochibraru"
|
|
18
18
|
},
|
|
19
19
|
"exports": {
|
|
20
|
-
".":
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"default": "./dist/index.js"
|
|
23
|
+
}
|
|
21
24
|
},
|
|
22
25
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"internal.d.ts",
|
|
25
|
-
"templates"
|
|
26
|
+
"dist"
|
|
26
27
|
],
|
|
27
28
|
"repository": {
|
|
28
29
|
"type": "git",
|
|
@@ -32,6 +33,8 @@
|
|
|
32
33
|
"access": "public"
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
36
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json && cp -R templates dist/templates",
|
|
37
|
+
"prepack": "bun run build",
|
|
35
38
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
36
39
|
"test": "bun test index.test.ts",
|
|
37
40
|
"test:integration": "bun test test/integration.test.ts",
|
package/index.ts
DELETED
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import { fileURLToPath } from "node:url";
|
|
2
|
-
import type { Adapter, Builder } from "@sveltejs/kit";
|
|
3
|
-
|
|
4
|
-
export interface AdapterOptions {
|
|
5
|
-
/**
|
|
6
|
-
* Output directory. Holds the compiled executable plus the `client/` and
|
|
7
|
-
* `prerendered/` folders it serves.
|
|
8
|
-
* @default "build"
|
|
9
|
-
*/
|
|
10
|
-
out?: string;
|
|
11
|
-
/**
|
|
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).
|
|
15
|
-
* @default "server"
|
|
16
|
-
*/
|
|
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;
|
|
29
|
-
/**
|
|
30
|
-
* Cross-compilation target for `bun build --compile`, e.g.
|
|
31
|
-
* `"bun-linux-x64"`, `"bun-linux-arm64-musl"`, `"bun-darwin-arm64"`,
|
|
32
|
-
* `"bun-windows-x64"` (optional `-modern` / `-baseline` SIMD suffix, and
|
|
33
|
-
* `-musl` for Alpine). Bun downloads the matching runtime on first use.
|
|
34
|
-
* @default the host platform
|
|
35
|
-
*/
|
|
36
|
-
target?: Bun.Build.CompileTarget;
|
|
37
|
-
/**
|
|
38
|
-
* Emit a V8 bytecode cache into the executable for faster cold starts, at
|
|
39
|
-
* the cost of a larger binary.
|
|
40
|
-
* @default false
|
|
41
|
-
*/
|
|
42
|
-
bytecode?: boolean;
|
|
43
|
-
/**
|
|
44
|
-
* Minify the bundled server code before embedding it.
|
|
45
|
-
* @default false
|
|
46
|
-
*/
|
|
47
|
-
minify?: boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Embed a source map so server stack traces point at original code.
|
|
50
|
-
* @default false
|
|
51
|
-
*/
|
|
52
|
-
sourcemap?: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Pre-compress client assets and prerendered pages to `.gz` / `.br`
|
|
55
|
-
* siblings. The handler serves them with the matching `Content-Encoding`
|
|
56
|
-
* when the request's `Accept-Encoding` allows.
|
|
57
|
-
* @default false
|
|
58
|
-
*/
|
|
59
|
-
precompress?: boolean;
|
|
60
|
-
/**
|
|
61
|
-
* Compile a second tiny executable, `healthcheck`, alongside the server
|
|
62
|
-
* and expose a matching `GET` endpoint. The binary probes that endpoint
|
|
63
|
-
* over loopback (or the Unix socket) and exits `0` when healthy, `1`
|
|
64
|
-
* otherwise — ready to drop into a Docker `HEALTHCHECK`. Pass an object
|
|
65
|
-
* to change the endpoint path.
|
|
66
|
-
* @default true
|
|
67
|
-
*/
|
|
68
|
-
healthcheck?: boolean | { path?: string };
|
|
69
|
-
/**
|
|
70
|
-
* Prefix for this adapter's own runtime env vars (`PORT`, `HOST`,
|
|
71
|
-
* `ORIGIN`, ...).
|
|
72
|
-
* @default ""
|
|
73
|
-
*/
|
|
74
|
-
envPrefix?: string;
|
|
75
|
-
/**
|
|
76
|
-
* Serve the app's static assets and prerendered pages from the
|
|
77
|
-
* executable. The `client/` and `prerendered/` folders must sit next to
|
|
78
|
-
* the binary (or point `ASSETS_DIR` at their parent). Turn off when a
|
|
79
|
-
* reverse proxy or CDN serves them instead.
|
|
80
|
-
* @default true
|
|
81
|
-
*/
|
|
82
|
-
serveAssets?: boolean;
|
|
83
|
-
/**
|
|
84
|
-
* Extra options merged into the `Bun.serve()` call (`tls`, `reusePort`,
|
|
85
|
-
* `maxConnections`, a custom `error` handler, ...). Applied *before* this
|
|
86
|
-
* adapter's own required fields (`idleTimeout`, `maxRequestBodySize`,
|
|
87
|
-
* `fetch`, `hostname`/`port`/`unix`, `websocket`), so it can't be used to
|
|
88
|
-
* override request handling, only to add to it. Use the existing env vars
|
|
89
|
-
* (`IDLE_TIMEOUT`, `BODY_SIZE_LIMIT`, `HOST`/`PORT`, `SOCKET_PATH`,
|
|
90
|
-
* `SHUTDOWN_TIMEOUT`) to change those instead.
|
|
91
|
-
* @default {}
|
|
92
|
-
*/
|
|
93
|
-
serveOptions?: Record<string, unknown>;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// `node:url`, not `Bun.fileURLToPath`: this module is loaded at config-parse
|
|
97
|
-
// time by Node-based tooling too (svelte-check, the Svelte language server,
|
|
98
|
-
// `svelte-kit sync`), where `Bun` is undefined. Everything that actually needs
|
|
99
|
-
// the Bun runtime lives inside `adapt()`.
|
|
100
|
-
const templates = fileURLToPath(new URL("./templates", import.meta.url));
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* SvelteKit adapter that compiles the app into a single standalone executable
|
|
104
|
-
* with `bun build --compile`.
|
|
105
|
-
*
|
|
106
|
-
* `adapt()` writes the SvelteKit server and this package's entrypoint templates
|
|
107
|
-
* into a temp directory, then compiles them — `@sveltejs/kit` and every other
|
|
108
|
-
* pure-JS dependency bundled in — into one binary. The build must run under the
|
|
109
|
-
* Bun runtime (`bun --bun vite build`, or a `bunfig.toml` with `[run] bun =
|
|
110
|
-
* true`); loading the config alone works under Node too.
|
|
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
|
-
*
|
|
116
|
-
* Output, all written to {@link AdapterOptions.out | `out`}:
|
|
117
|
-
*
|
|
118
|
-
* ```text
|
|
119
|
-
* build/
|
|
120
|
-
* ├── server the executable (rename with `name`)
|
|
121
|
-
* ├── client/ static assets, served by the executable
|
|
122
|
-
* └── prerendered/ prerendered pages, served by the executable
|
|
123
|
-
* ```
|
|
124
|
-
*
|
|
125
|
-
* The executable resolves `client/` and `prerendered/` from its own location
|
|
126
|
-
* (`dirname(process.execPath)`, overridable with the `ASSETS_DIR` env var), so
|
|
127
|
-
* it can run from any working directory. Deploy the whole `out` directory, or
|
|
128
|
-
* just the binary when {@link AdapterOptions.serveAssets | `serveAssets`} is
|
|
129
|
-
* off and a proxy/CDN serves the assets.
|
|
130
|
-
*
|
|
131
|
-
* Runtime configuration (`HOST`, `PORT`, `ORIGIN`, `BODY_SIZE_LIMIT`, …) is
|
|
132
|
-
* read from environment variables, optionally namespaced by
|
|
133
|
-
* {@link AdapterOptions.envPrefix | `envPrefix`}.
|
|
134
|
-
*
|
|
135
|
-
* @param options - see {@link AdapterOptions}
|
|
136
|
-
* @returns the configured SvelteKit {@link Adapter}
|
|
137
|
-
*
|
|
138
|
-
* @example
|
|
139
|
-
* ```js
|
|
140
|
-
* // svelte.config.js
|
|
141
|
-
* import adapter from "@orochibraru/svelte-smol";
|
|
142
|
-
*
|
|
143
|
-
* export default {
|
|
144
|
-
* kit: {
|
|
145
|
-
* adapter: adapter({
|
|
146
|
-
* // cross-compile for an Alpine container from any host
|
|
147
|
-
* target: "bun-linux-x64-musl",
|
|
148
|
-
* bytecode: true,
|
|
149
|
-
* }),
|
|
150
|
-
* },
|
|
151
|
-
* };
|
|
152
|
-
* ```
|
|
153
|
-
*
|
|
154
|
-
* @see {@link https://bun.com/docs/bundler/executables | Bun — Single-file executables}
|
|
155
|
-
*/
|
|
156
|
-
export default function adapter(options: AdapterOptions = {}): Adapter {
|
|
157
|
-
const {
|
|
158
|
-
out = "build",
|
|
159
|
-
name = "server",
|
|
160
|
-
compile = true,
|
|
161
|
-
target,
|
|
162
|
-
bytecode = false,
|
|
163
|
-
minify = false,
|
|
164
|
-
sourcemap = false,
|
|
165
|
-
precompress = false,
|
|
166
|
-
healthcheck = true,
|
|
167
|
-
envPrefix = "",
|
|
168
|
-
serveAssets = true,
|
|
169
|
-
serveOptions = {},
|
|
170
|
-
} = options;
|
|
171
|
-
|
|
172
|
-
const healthcheckConfig =
|
|
173
|
-
healthcheck === false
|
|
174
|
-
? false
|
|
175
|
-
: {
|
|
176
|
-
path:
|
|
177
|
-
(healthcheck === true ? undefined : healthcheck.path) ?? "/_health",
|
|
178
|
-
};
|
|
179
|
-
|
|
180
|
-
return {
|
|
181
|
-
name: "@orochibraru/svelte-smol",
|
|
182
|
-
supports: {
|
|
183
|
-
instrumentation: () => true,
|
|
184
|
-
read: () => true,
|
|
185
|
-
},
|
|
186
|
-
async adapt(builder: Builder) {
|
|
187
|
-
const { base } = builder.config.kit.paths;
|
|
188
|
-
const tmp = builder.getBuildDirectory("adapter-bun");
|
|
189
|
-
|
|
190
|
-
builder.rimraf(out);
|
|
191
|
-
builder.rimraf(tmp);
|
|
192
|
-
builder.mkdirp(`${out}/`);
|
|
193
|
-
builder.mkdirp(tmp);
|
|
194
|
-
|
|
195
|
-
builder.log.minor("Copying assets");
|
|
196
|
-
builder.writeClient(`${out}/client${base}`);
|
|
197
|
-
builder.writePrerendered(`${out}/prerendered${base}`);
|
|
198
|
-
|
|
199
|
-
if (precompress) {
|
|
200
|
-
builder.log.minor("Compressing assets");
|
|
201
|
-
await Promise.all([
|
|
202
|
-
builder.compress(`${out}/client`),
|
|
203
|
-
builder.compress(`${out}/prerendered`),
|
|
204
|
-
]);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
builder.log.minor("Building server");
|
|
208
|
-
builder.writeServer(`${tmp}/server`);
|
|
209
|
-
await Bun.write(
|
|
210
|
-
`${tmp}/server/manifest.js`,
|
|
211
|
-
[
|
|
212
|
-
`export const manifest = ${builder.generateManifest({ relativePath: "./" })};`,
|
|
213
|
-
`export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});`,
|
|
214
|
-
`export const base = ${JSON.stringify(base)};`,
|
|
215
|
-
].join("\n\n"),
|
|
216
|
-
);
|
|
217
|
-
|
|
218
|
-
// Entry templates ship as raw `.ts` — `bun build --compile` runs them
|
|
219
|
-
// straight through. The virtual specifiers (`ENV`, `MANIFEST`,
|
|
220
|
-
// `SERVER`, `HANDLER`) and the `ENV_PREFIX` / `BUILD_OPTIONS` /
|
|
221
|
-
// `SERVE_OPTIONS` tokens are resolved by this raw word-boundary token
|
|
222
|
-
// swap over the copied source.
|
|
223
|
-
builder.log.minor("Copying entrypoint");
|
|
224
|
-
builder.copy(templates, tmp, {
|
|
225
|
-
replace: {
|
|
226
|
-
BUILD_OPTIONS: JSON.stringify({
|
|
227
|
-
serveAssets,
|
|
228
|
-
precompress,
|
|
229
|
-
healthcheck: healthcheckConfig,
|
|
230
|
-
compiled: compile,
|
|
231
|
-
}),
|
|
232
|
-
ENV: "./env.ts",
|
|
233
|
-
ENV_PREFIX: JSON.stringify(envPrefix),
|
|
234
|
-
HANDLER: "./handler.ts",
|
|
235
|
-
MANIFEST: "./server/manifest.js",
|
|
236
|
-
SERVE_OPTIONS: JSON.stringify(serveOptions),
|
|
237
|
-
SERVER: "./server/index.js",
|
|
238
|
-
},
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
const entry = `${tmp}/index.ts`;
|
|
242
|
-
if (builder.hasServerInstrumentationFile?.()) {
|
|
243
|
-
// Instrumentation (OpenTelemetry &c.) has to load before anything
|
|
244
|
-
// else in the bundle. A compiled binary has no post-build
|
|
245
|
-
// entrypoint to rewrite, so prepend the import to the compile
|
|
246
|
-
// entrypoint instead.
|
|
247
|
-
await Bun.write(
|
|
248
|
-
entry,
|
|
249
|
-
`import "./server/instrumentation.server.js";\n${await Bun.file(entry).text()}`,
|
|
250
|
-
);
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const check = (
|
|
254
|
-
result: Awaited<ReturnType<typeof Bun.build>>,
|
|
255
|
-
label: string,
|
|
256
|
-
) => {
|
|
257
|
-
if (!result.success) {
|
|
258
|
-
for (const message of result.logs) {
|
|
259
|
-
builder.log.error(String(message));
|
|
260
|
-
}
|
|
261
|
-
throw new Error(`\`bun build\` failed for ${label}`);
|
|
262
|
-
}
|
|
263
|
-
};
|
|
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
|
-
);
|
|
283
|
-
builder.log.success(`Compiled ${out}/${outName}`);
|
|
284
|
-
};
|
|
285
|
-
|
|
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
|
-
}
|
|
314
|
-
if (healthcheckConfig) {
|
|
315
|
-
await compileBinary(`${tmp}/healthcheck.ts`, "healthcheck");
|
|
316
|
-
}
|
|
317
|
-
},
|
|
318
|
-
};
|
|
319
|
-
}
|
package/internal.d.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
// Ambient declarations for the virtual specifiers/globals `templates/*.ts`
|
|
2
|
-
// reference. None of these are real modules or runtime globals at
|
|
3
|
-
// type-check time, `index.ts`'s adapt() resolves them via a raw text
|
|
4
|
-
// replacement over the compiled output (see its `builder.copy(..., {
|
|
5
|
-
// replace })` call), so this file exists purely so `templates/*.ts`
|
|
6
|
-
// typechecks against the shape that replacement actually produces.
|
|
7
|
-
|
|
8
|
-
declare module "ENV" {
|
|
9
|
-
export function env(name: string, fallback: string): string;
|
|
10
|
-
export function env(name: string, fallback: false): string | false;
|
|
11
|
-
export function env(name: string, fallback?: undefined): string | undefined;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
declare module "HANDLER" {
|
|
15
|
-
export function getHandler(): {
|
|
16
|
-
fetch: (
|
|
17
|
-
request: Request,
|
|
18
|
-
server: Bun.Server<undefined>,
|
|
19
|
-
) => Response | Promise<Response>;
|
|
20
|
-
websocket: Bun.WebSocketHandler<undefined> | undefined;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
declare module "MANIFEST" {
|
|
25
|
-
import type { SSRManifest } from "@sveltejs/kit";
|
|
26
|
-
|
|
27
|
-
export const base: string;
|
|
28
|
-
export const manifest: SSRManifest;
|
|
29
|
-
export const prerendered: Set<string>;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
declare module "SERVER" {
|
|
33
|
-
export { Server } from "@sveltejs/kit";
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
declare const ENV_PREFIX: string;
|
|
37
|
-
declare const BUILD_OPTIONS: {
|
|
38
|
-
serveAssets: boolean;
|
|
39
|
-
precompress: boolean;
|
|
40
|
-
healthcheck: false | { path: string };
|
|
41
|
-
compiled: boolean;
|
|
42
|
-
};
|
|
43
|
-
declare const SERVE_OPTIONS: Record<string, unknown>;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|