sveltekit-adapter-bare
v0.2.0
Published
sveltekit-adapter-bare
Readme
sveltekit-adapter-bare
⚠️ Highly experimental. This adapter is a proof of concept for running a SvelteKit app inside the bare runtime so it can be packaged with
bare-buildand rendered in a native window viabare-native. Expect rough edges, missing features, and breaking changes.
A SvelteKit adapter that produces a server bundle runnable by bare instead of Node.js. The output is a plain build/ directory you can hand to bare-build to produce a single-file, native-windowed app.

Demo: https://github.com/Drache93/bare-svelte-demo
Install
npm install --save-dev sveltekit-adapter-bareAll bare runtime deps (bare-http1, bare-fs, bare-native, bare-fetch, bare-form-data, paparam, etc.) are pulled in transitively — you don't need to declare them in your own package.json.
Configure
In svelte.config.js, swap out your adapter:
import adapter from 'sveltekit-adapter-bare'
/** @type {import('@sveltejs/kit').Config} */
const config = {
compilerOptions: {
// Force runes mode for the project, except for libraries. Can be removed in svelte 6.
runes: ({ filename }) => (filename.split(/[/\\]/).includes('node_modules') ? undefined : true)
},
kit: {
adapter: adapter({
window: { width: 1200, height: 800, inspectable: false }
}),
csrf: { checkOrigin: false }
}
}
export default configOptions:
| option | default | description |
| --- | --- | --- |
| out | 'build' | Directory to emit the server bundle. |
| window.width | 800 | Native window width in pixels. |
| window.height | 600 | Native window height in pixels. |
| window.inspectable | false | Enable the WebView's remote DevTools inspector. |
Vite plugin
Add vitePlugin() to vite.config.ts to automatically externalize all bare-* packages from Vite's SSR bundler. Without this, Vite tries to bundle native Bare modules and fails.
import { vitePlugin as bareExternals } from 'sveltekit-adapter-bare'
import { sveltekit } from '@sveltejs/kit/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [sveltekit(), bareExternals()],
ssr: {
// vitePlugin handles bare-* automatically; add non-bare holepunch packages manually:
external: ['distributed-drive', 'hyperdb', 'corestore', 'hyperswarm', 'hyperdrive', ...]
}
})Graceful shutdown and sveltekit:close
The adapter fires sveltekit:close on process exit (Ctrl-C, SIGTERM, and native window close). Use it to tear down long-lived resources:
// src/hooks.server.ts
process.on('sveltekit:close', async () => {
await app?.close()
})macOS window close caveat: AppKitWindow emits will-close but the NativeWindow wrapper does not forward it. The adapter hooks win._native?.on?.('will-close', shutdown) directly, so Ctrl-X on the window triggers the same clean shutdown as Ctrl-C.
Build
Three steps — SvelteKit produces the bare-compatible server, bare-build links it for a target platform against the bare-native runtime, and bare-build wraps the result into a native app:
# 1. Vite build — the adapter emits ./build
npm run build
# 2. Build the native app for the target host/arch using the bare-native runtime
npx bare-build \
--out build/darwin-arm64 \
--host darwin-arm64 \
--runtime bare-native/runtime \
build/index.jsSwap --host / --out to target a different platform (linux-x64, android-arm64, etc.).
The emitted entry (build/index.js) is a small paparam CLI that spins up bare-http1, opens a bare-native window, and loads http://localhost:<port>:
./build/<platform>/<name>.app --width 800 --height 600 --inspectableFlags:
--host(default0.0.0.0) — interface to listen on.--port(default0) — TCP port.0asks the OS for a free port; the chosen port is logged at startup and handed to the WebView automatically.--width,--height— native window size (overridewindowoption fromsvelte.config.js).--inspectable— enable the WebView's remote inspector (connect from desktop Chrome viachrome://inspect).
What the adapter does
- Bundles SvelteKit's server with
esbuild, aliasingnode:*builtins to theirbare-*equivalents. - Patches out SvelteKit's lazy
obfuscated_import("node:crypto")fallback —globalThis.cryptois assigned at startup frombare-crypto. - Stubs
node:async_hooks(bare doesn't ship an equivalent; SvelteKit'sAsyncLocalStorageusage works against a minimal shim). - Emits an
assets.jsmodule with one staticimport.meta.asset()call per file inclient/andprerendered/, sobare-module-traversepreserves every static asset whenbare-buildbundles the app. - Correctly forwards multiple
Set-Cookieheaders usinggetSetCookie()instead of flattening them.
Known limitations
multipart/form-datafile uploads are not implemented (text fields only).- No HTTPS, no clustering, no compression, no range requests.
License
Apache-2.0
