{"_id":"@k2b/ssr","_rev":"5-a9c86bb8f95c308741834bb5da92b6ac","name":"@k2b/ssr","dist-tags":{"latest":"0.14.0"},"versions":{"0.12.0-rc.0":{"name":"@k2b/ssr","version":"0.12.0-rc.0","keywords":["solid","solidjs","ssr","bun","server-side-rendering","islands","elysia","hono"],"author":{"name":"Valentin Kolb"},"license":"MIT","_id":"@k2b/ssr@0.12.0-rc.0","maintainers":[{"name":"valentinkolb","email":"mail@valentin-kolb.com"}],"homepage":"https://github.com/k2b-dev/ssr#readme","bugs":{"url":"https://github.com/k2b-dev/ssr/issues"},"dist":{"shasum":"c36291fe319a0b8cc4cf50389e90fc7e75decc85","tarball":"https://registry.npmjs.org/@k2b/ssr/-/ssr-0.12.0-rc.0.tgz","fileCount":14,"integrity":"sha512-lQ+sN+ugcU6M0V24aoZdZ5BCS5Q//uOR3KSExqsNmmpnHT+0em0IyjNzH/JwQ3B7nUzpe//Nca4EVVrrUkny0A==","signatures":[{"sig":"MEUCIQDk6lLsdS00YN3/FwrZK/1UM5gKA8UWzOhCwyN+KRJdlAIgQhxJqYno48VUP6Hr0WbS4kN5UKh5is3ngK16mkkzyQk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":76669},"main":"src/index.ts","type":"module","types":"src/index.ts","exports":{".":"./src/index.ts","./bun":"./src/adapter/bun.ts","./nav":"./src/nav.ts","./hono":"./src/adapter/hono.ts","./elysia":"./src/adapter/elysia.ts"},"scripts":{"test":"bunx tsc -p test/tsconfig.json && bun test test/unit && bun test --conditions=browser --preload ./test/browser/setup.ts test/browser"},"_npmUser":{"name":"valentinkolb","email":"mail@valentin-kolb.com"},"repository":{"url":"git+https://github.com/k2b-dev/ssr.git","type":"git"},"_npmVersion":"12.0.1","description":"Minimal SSR framework for SolidJS and Bun","directories":{},"_nodeVersion":"24.15.0","dependencies":{"seroval":"^1.5.5","@babel/core":"^7.29.7","@types/babel__core":"^7.20.5","babel-preset-solid":"^1.9.12","@babel/preset-typescript":"^7.29.7"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.30","elysia":"^1.4.29","solid-js":"^1.9.14","file-type":"^21.3.1","@types/bun":"^1.3.14","typescript":"^5.9.3","@happy-dom/global-registrator":"^20.10.6"},"peerDependencies":{"hono":"^4.0.0","elysia":"^1.0.0","solid-js":"^1.9.0"},"peerDependenciesMeta":{"hono":{"optional":true},"elysia":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ssr_0.12.0-rc.0_1785084029042_0.13619045583013967","host":"s3://npm-registry-packages-npm-production"}},"0.12.0":{"name":"@k2b/ssr","version":"0.12.0","keywords":["solid","solidjs","ssr","bun","server-side-rendering","islands","elysia","hono"],"author":{"name":"Valentin Kolb"},"license":"MIT","_id":"@k2b/ssr@0.12.0","maintainers":[{"name":"valentinkolb","email":"mail@valentin-kolb.com"}],"homepage":"https://github.com/k2b-dev/ssr#readme","bugs":{"url":"https://github.com/k2b-dev/ssr/issues"},"dist":{"shasum":"c9e34a0ad23e14f6db96d99ecba352501dd5bcf7","tarball":"https://registry.npmjs.org/@k2b/ssr/-/ssr-0.12.0.tgz","fileCount":14,"integrity":"sha512-71Yg65mfkpVuBSaq0m+QZyvw5KL4uvFVKnZREjNmXVf0K4+IpNWbCcM+fVXbPnzVMr48+FEM9n0/c1E6Jq7yPA==","signatures":[{"sig":"MEUCIQCP05oQShiEmg/WljQourUYc4lRZLXuvkoIOO8vpwGbNAIgQzr/FFOkiUWVa+wn3gjRwPehwwBNIH1eQHNohanvPeM=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@k2b%2fssr@0.12.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":76664},"main":"src/index.ts","type":"module","types":"src/index.ts","exports":{".":"./src/index.ts","./bun":"./src/adapter/bun.ts","./nav":"./src/nav.ts","./hono":"./src/adapter/hono.ts","./elysia":"./src/adapter/elysia.ts"},"gitHead":"ed26c34942ca9b25cf56cfff8ffb69321136cc54","scripts":{"test":"bunx tsc -p test/tsconfig.json && bun test test/unit && bun test --conditions=browser --preload ./test/browser/setup.ts test/browser"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:eae4b070-bb9e-4f1d-abea-238591249ac7"}},"repository":{"url":"git+https://github.com/k2b-dev/ssr.git","type":"git"},"_npmVersion":"11.16.0","description":"Minimal SSR framework for SolidJS and Bun","directories":{},"_nodeVersion":"24.18.0","dependencies":{"seroval":"^1.5.5","@babel/core":"^7.29.7","@types/babel__core":"^7.20.5","babel-preset-solid":"^1.9.12","@babel/preset-typescript":"^7.29.7"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.30","elysia":"^1.4.29","solid-js":"^1.9.14","file-type":"^21.3.1","@types/bun":"^1.3.14","typescript":"^5.9.3","@happy-dom/global-registrator":"^20.10.6"},"peerDependencies":{"hono":"^4.0.0","elysia":"^1.0.0","solid-js":"^1.9.0"},"peerDependenciesMeta":{"hono":{"optional":true},"elysia":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ssr_0.12.0_1785084155182_0.4759532432176876","host":"s3://npm-registry-packages-npm-production"}},"0.13.1":{"name":"@k2b/ssr","version":"0.13.1","keywords":["solid","solidjs","ssr","bun","server-side-rendering","islands","elysia","hono"],"author":{"name":"Valentin Kolb"},"license":"MIT","_id":"@k2b/ssr@0.13.1","maintainers":[{"name":"valentinkolb","email":"mail@valentin-kolb.com"}],"homepage":"https://github.com/k2b-dev/ssr#readme","bugs":{"url":"https://github.com/k2b-dev/ssr/issues"},"dist":{"shasum":"1ae554661290fb31624bdef84880e099a6ecb376","tarball":"https://registry.npmjs.org/@k2b/ssr/-/ssr-0.13.1.tgz","fileCount":14,"integrity":"sha512-WDm/3dI9q2ikf8V7RgPdfgqF9DSMAaUDQC9sx9+8eAYp/l4XpkQTVRGta+pb9BYFR+bTGSn/enCt9yaPihR3Hw==","signatures":[{"sig":"MEUCIQDXD0WjyPpGT3r+iATi8of5/eodIN/o9uuWQ6Lxv/k2igIgf4lHZdqv6501MpLeu4rsvdYCUda8MfWVJxOcSOTcRYg=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC+Ptx+bitm/egj9i0eE8+IrL074//vrqLEqZD8M6uYtQIgI/6U74IFTcudZx47Sq0x7LqAOj62FCGfaX0SimXnpYc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@k2b%2fssr@0.13.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":79836},"main":"src/index.ts","type":"module","types":"src/index.ts","exports":{".":"./src/index.ts","./bun":"./src/adapter/bun.ts","./nav":"./src/nav.ts","./hono":"./src/adapter/hono.ts","./elysia":"./src/adapter/elysia.ts"},"gitHead":"7d37e38b6efbd79624de4c2f5265917704bbd994","scripts":{"test":"bunx tsc -p test/tsconfig.json && bun test test/unit && bun test --conditions=browser --preload ./test/browser/setup.ts test/browser"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:eae4b070-bb9e-4f1d-abea-238591249ac7"}},"repository":{"url":"git+https://github.com/k2b-dev/ssr.git","type":"git"},"_npmVersion":"11.19.0","description":"Minimal SSR framework for SolidJS and Bun","directories":{},"_nodeVersion":"24.20.0","dependencies":{"seroval":"^1.5.5","@babel/core":"^7.29.7","@types/babel__core":"^7.20.5","babel-preset-solid":"^1.9.12","@babel/preset-typescript":"^7.29.7"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.30","elysia":"^1.4.29","solid-js":"^1.9.14","file-type":"^21.3.1","@types/bun":"^1.3.14","typescript":"^5.9.3","@happy-dom/global-registrator":"^20.10.6"},"peerDependencies":{"hono":"^4.0.0","elysia":"^1.0.0","solid-js":"^1.9.0"},"peerDependenciesMeta":{"hono":{"optional":true},"elysia":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/ssr_0.13.1_1789329520764_0.41082139512863036","host":"s3://npm-registry-packages-npm-production"}},"0.14.0":{"_id":"@k2b/ssr@0.14.0","bugs":{"url":"https://github.com/k2b-dev/ssr/issues"},"dist":{"shasum":"50fcc5f8eba8338798543b2b63ea1e88a0ded3a8","tarball":"https://registry.npmjs.org/@k2b/ssr/-/ssr-0.14.0.tgz","fileCount":14,"integrity":"sha512-/fkn1Vs7upKv8nsG3edHV8Q1rrtm5oJ+ZkodnqdxRd9+/EKf9qoxSN1oFUP8+x/6K8e+DkP9iAHGdNa/HXEf7A==","signatures":[{"sig":"MEUCIE1+3KmXTyZeelYCXHPF5Susu2NZLmoGYeNesOeUsbZUAiEA8iRrHUzDYKx81CpDnB+hDgp53yNkT/M3cOkeN5OFdSQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDlLQsronqw3aiZ6mD1c4oNuNOdL9ziQDmY6BmRFdqsHwIhAKddC6IgegwK+dNI+GbbUPN7hEWw5nnW9PhW8VibPgxV"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@k2b%2fssr@0.14.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":82221},"main":"src/index.ts","name":"@k2b/ssr","type":"module","types":"src/index.ts","author":{"name":"Valentin Kolb"},"exports":{".":"./src/index.ts","./bun":"./src/adapter/bun.ts","./nav":"./src/nav.ts","./hono":"./src/adapter/hono.ts","./elysia":"./src/adapter/elysia.ts"},"gitHead":"5557cc73e2dcba8c1e81925f252e8ae1f6954f6e","license":"MIT","scripts":{"test":"bunx tsc -p test/tsconfig.json && bun test test/unit && bun test --conditions=browser --preload ./test/browser/setup.ts test/browser"},"version":"0.14.0","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:eae4b070-bb9e-4f1d-abea-238591249ac7"}},"homepage":"https://github.com/k2b-dev/ssr#readme","keywords":["solid","solidjs","ssr","bun","server-side-rendering","islands","elysia","hono"],"repository":{"url":"git+https://github.com/k2b-dev/ssr.git","type":"git"},"_npmVersion":"11.19.0","description":"Minimal SSR framework for SolidJS and Bun","directories":{},"maintainers":[{"name":"valentinkolb","email":"mail@valentin-kolb.com"}],"_nodeVersion":"24.20.0","dependencies":{"seroval":"^1.5.5","@babel/core":"^7.29.7","@types/babel__core":"^7.20.5","babel-preset-solid":"^1.9.12","@babel/preset-typescript":"^7.29.7"},"_hasShrinkwrap":false,"devDependencies":{"hono":"^4.12.30","elysia":"^1.4.29","solid-js":"^1.9.14","file-type":"^21.3.1","@types/bun":"1.4.2","typescript":"^5.9.3","@happy-dom/global-registrator":"^20.10.6"},"peerDependencies":{"hono":"^4.0.0","elysia":"^1.0.0","solid-js":"^1.9.0"},"peerDependenciesMeta":{"hono":{"optional":true},"elysia":{"optional":true}},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ssr_0.14.0_1789437335406_0.46314021471741174"}}},"time":{"created":"2026-07-26T16:40:28.867Z","modified":"2026-09-15T01:55:35.816Z","0.12.0-rc.0":"2026-07-26T16:40:29.173Z","0.12.0":"2026-07-26T16:42:35.335Z","0.13.1":"2026-09-13T19:58:40.848Z","0.14.0":"2026-09-15T01:55:35.493Z"},"bugs":{"url":"https://github.com/k2b-dev/ssr/issues"},"author":{"name":"Valentin Kolb"},"license":"MIT","homepage":"https://github.com/k2b-dev/ssr#readme","keywords":["solid","solidjs","ssr","bun","server-side-rendering","islands","elysia","hono"],"repository":{"url":"git+https://github.com/k2b-dev/ssr.git","type":"git"},"description":"Minimal SSR framework for SolidJS and Bun","maintainers":[{"name":"valentinkolb","email":"mail@valentin-kolb.com"}],"readme":"# @k2b/ssr\n\nMinimal SSR + islands framework for SolidJS on Bun.\n\n## Overview\n\nThis library renders Solid components on the server and hydrates only interactive islands on the client.\n\nIt uses file conventions:\n\n- `*.island.tsx`: SSR + hydrated on the client\n- `*.client.tsx`: client-only (no SSR HTML content)\n- `*.tsx`: server-only output\n\n## Size & Philosophy\n\nThis framework is intentionally minimal and focused on SSR + islands only.\n\nCurrent source size in this repo (`packages/ssr-core/src`):\n\n| Component | Lines | Raw | Gzipped |\n| --- | ---: | ---: | ---: |\n| Core (`index`, `transform`, `build`, island ID + resolver) | ~750 | 26.2 KB | 8.3 KB |\n| Dev client (overlay + reload, dev only) | ~421 | 11.9 KB | 3.5 KB |\n| Adapters (`bun`, `hono`, `elysia`, shared utils) | ~465 | 14.4 KB | 4.8 KB |\n\nImportant: these sizes describe framework source code that runs at build time and on the server.\nThe browser receives only:\n\n- your island bundles\n- Solid runtime from your app dependencies\n- `seroval` deserialize runtime\n- a tiny hydration import snippet\n\nFramework overhead in the browser is intentionally small.\n\nWhat is intentionally not included:\n\n- no client-side router\n- no state management layer\n- no CSS-in-JS abstraction\n- no build tool wrapper around Bun\n\nUse the libraries you already prefer. This package only handles SSR and islands hydration.\nThe optional `@k2b/ssr/nav` subpath provides progressive anchor\nenhancement for islands, but it still does not add route matching, loaders, or\nSPA routing.\n\n## Features\n\n- Small SSR core with Bun-native build/plugin flow\n- Adapters for Bun, Hono, and Elysia\n- Type-safe Hono page helper via `createSSRHandler`\n- Optional progressive navigation helpers via `@k2b/ssr/nav`\n- Monorepo support via `rootDir`\n- Public path mounting via `basePath` for microfrontends\n- Stable file-path-based island IDs (collision-safe across workspace packages)\n- Production module cache busting (`/_ssr/<buildTimestamp>/*.js`)\n- Linked development source maps and validator-aware asset delivery\n- Stale generated island assets removed after successful builds\n- Visibility-aware development reload with cross-tab SSE coordination\n\n## Install\n\n```bash\nbun add @k2b/ssr solid-js\n\n# choose adapter deps you need\nbun add hono\n# or\nbun add elysia\n```\n\n### Package scope migration\n\n`@k2b/ssr` is the maintained successor to `@valentinkolb/ssr`. There are no\nframework API changes in the scope migration. Replace the dependency and all\nroot or subpath imports:\n\n```ts\n// Before\nimport { createConfig } from \"@valentinkolb/ssr\";\nimport { routes } from \"@valentinkolb/ssr/hono\";\n\n// After\nimport { createConfig } from \"@k2b/ssr\";\nimport { routes } from \"@k2b/ssr/hono\";\n```\n\n## Required TypeScript settings\n\n```json\n{\n  \"compilerOptions\": {\n    \"lib\": [\"ESNext\", \"DOM\"],\n    \"jsx\": \"preserve\",\n    \"jsxImportSource\": \"solid-js\",\n    \"moduleResolution\": \"bundler\"\n  }\n}\n```\n\n## Quick Start (Hono)\n\n### 1) Create config\n\n```ts\n// config.ts\nimport { createConfig } from \"@k2b/ssr\";\nimport { createSSRHandler, routes } from \"@k2b/ssr/hono\";\n\ntype PageOptions = {\n  title?: string;\n  description?: string;\n};\n\nexport const { config, plugin, html } = createConfig<PageOptions>({\n  dev: process.env.NODE_ENV === \"development\",\n  // For monorepos with separated packages:\n  // rootDir: \"/path/to/workspace-root\",\n  // For microfrontends mounted under /docs:\n  // basePath: \"/docs\",\n  template: ({ body, scripts, title, description }) => `\n    <!doctype html>\n    <html>\n      <head>\n        <meta charset=\"utf-8\" />\n        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n        <title>${title ?? \"App\"}</title>\n        ${description ? `<meta name=\"description\" content=\"${description}\">` : \"\"}\n      </head>\n      <body>${body}${scripts}</body>\n    </html>\n  `,\n});\n\nexport const ssr = createSSRHandler(html);\nexport { routes };\n```\n\n### 2) Register plugin in dev\n\n```ts\n// scripts/preload.ts\nimport { plugin } from \"../config\";\n\nBun.plugin(plugin());\n```\n\n### 3) Create an island\n\n```tsx\n// components/Counter.island.tsx\nimport { createSignal } from \"solid-js\";\n\nexport default function Counter({ initial = 0 }: { initial?: number }) {\n  const [count, setCount] = createSignal(initial);\n  return <button onClick={() => setCount((c) => c + 1)}>Count: {count()}</button>;\n}\n```\n\n### 4) Create a page\n\n```tsx\n// pages/Home.tsx\nimport { ssr } from \"../config\";\nimport Counter from \"../components/Counter.island\";\n\nexport default ssr(async (c) => {\n  c.get(\"page\").title = \"Home\";\n  return () => <Counter initial={5} />;\n});\n```\n\n### 5) Wire server\n\n```ts\n// server.ts\nimport { Hono } from \"hono\";\nimport { config, routes } from \"./config\";\nimport Home from \"./pages/Home\";\n\nexport default new Hono()\n  .route(\"/_ssr\", routes(config))\n  .get(\"/\", ...Home);\n```\n\n### 6) Run\n\n```bash\nNODE_ENV=development bun --watch --preload=./scripts/preload.ts src/server.ts\n```\n\n## Adapter imports\n\n- Bun: `@k2b/ssr/bun`\n- Hono: `@k2b/ssr/hono`\n- Elysia: `@k2b/ssr/elysia`\n\n## Optional Navigation Helpers\n\n`@k2b/ssr/nav` is an opt-in browser helper for islands that want to\nupdate URL history after they have already updated client state.\n\n```tsx\nimport { createSignal, onCleanup, onMount } from \"solid-js\";\nimport { Link, listenPopState, type LinkNavigateEvent } from \"@k2b/ssr/nav\";\n\nexport default function Tabs() {\n  const [tab, setTab] = createSignal(\"alpha\");\n\n  onMount(() => {\n    onCleanup(\n      listenPopState(({ url }) => {\n        setTab(url.searchParams.get(\"tab\") ?? \"alpha\");\n      }),\n    );\n  });\n\n  const openTab = (nav: LinkNavigateEvent) => {\n    const next = nav.url.searchParams.get(\"tab\") ?? \"alpha\";\n    setTab(next);\n    nav.push(`/demo?tab=${next}`, { scroll: \"preserve\", state: { tab: next } });\n  };\n\n  return (\n    <Link href=\"/demo?tab=beta\" scroll=\"preserve\" onNavigate={openTab}>\n      Open beta\n    </Link>\n  );\n}\n```\n\n`Link` renders a real `<a href>` during SSR. Enhanced clicks only run in the\nbrowser for same-origin, left-click navigation without modifier keys. Without\n`onNavigate`, `Link` calls `navigate()` directly and only updates browser\nhistory. With `onNavigate`, the island owns data loading and state updates, then\ncalls `nav.push()`, `nav.replaceWith()`, or `nav.fallback()`.\n\nUse `listenPopState()` whenever `nav.push()` represents client state. Browser\nBack/Forward changes history but cannot infer how an island maps the URL back to\nsignals or stores. The helper reports the current `URL`, native `PopStateEvent`,\nand history state without adding route matching or data loading.\n\nNavigation behavior:\n\n- reactive anchor props remain reactive after `Link` renders\n- same-document hash links retain native target scrolling unless `onNavigate`\n  or `scroll` explicitly takes ownership\n- relative URLs follow `document.baseURI`\n- cross-origin `navigate()` calls use full document navigation\n- replace navigation preserves existing `history.state` unless `state` is set\n- rejected async `onNavigate` callbacks log the error and fall back to a full\n  document navigation\n\nAvailable exports:\n\n- `Link`\n- `navigate()`, `navigateTo()`, `documentNavigate()`, `currentPathWithQuery()`, `refreshCurrentPath()`\n- `captureScroll()`, `restoreScroll()`, `listenPopState()`, `startViewTransition()`\n- `LinkNavigateEvent`, `LinkProps`, `EnhancedNavigateOptions`, `NavigationScrollMode`, `PopStateNavigationEvent`, `ScrollSnapshot`\n\nUse `data-scroll-preserve=\"stable-key\"` on scroll containers that should keep\ntheir scroll position across enhanced navigation.\n\n## Rendering API\n\n`html()` and Hono `ssr()` handlers expect a synchronous render function:\n\n```tsx\nexport default ssr(async (c) => {\n  const data = await loadData();\n  c.get(\"page\").title = data.title;\n\n  return () => <Page data={data} />;\n});\n\napp.get(\"/\", () => html(() => <Page />));\n```\n\nDo async work in the handler before returning the render function. Do not make the render function itself `async`; Solid SSR expects synchronous JSX evaluation.\n\n### v0.9.0 migration\n\nThis is a breaking change in v0.9.0. In v0.8.x and earlier, examples often returned already-created JSX:\n\n```tsx\n// v0.8.x and earlier\nexport default ssr(async () => <Page />);\n\napp.get(\"/\", () => html(<Page />));\n```\n\nIn v0.9.0, wrap JSX creation in a render function:\n\n```tsx\n// v0.9.0+\nexport default ssr(async () => () => <Page />);\n\napp.get(\"/\", () => html(() => <Page />));\n```\n\nThis ensures Solid primitives such as `createUniqueId()` run inside `renderToString()`, where the SSR context exists.\n\n## `createConfig` options\n\n```ts\ncreateConfig({\n  dev?: boolean;         // default: false\n  verbose?: boolean;     // default: !dev\n  rootDir?: string;      // default: process.cwd()\n  componentRoots?: readonly string[]; // explicit island/client discovery directories\n  basePath?: string;     // default: \"\", example: \"/docs\"\n  external?: string[];   // passed to Bun.build for island bundle\n  devSourcemap?: \"none\" | \"linked\" | \"inline\"; // default: \"linked\"\n  template?: ({ body, scripts, ...custom }) => string | Promise<string>;\n})\n```\n\n### Notes\n\n- `rootDir` is important in monorepos where server entrypoint and island files live in different packages.\n- `componentRoots` replaces the discovery scan with explicit directories. Relative paths resolve against `rootDir`; absolute paths support installed framework packages. Omit it to scan `rootDir`, or pass `[]` to scan nothing. Missing directories fail the build. Symlinks and overlapping roots are deduplicated by canonical path; nested `node_modules` and `.git` directories are skipped. Select an installed package directory explicitly to scan its components.\n- Solid core, web, and store imports use the app's dependency and the selected build mode consistently, including components imported from installed packages.\n- `rootDir` still controls component IDs and the development asset directory. All selected components share one browser build. Ordinary component libraries with browser/SSR exports (such as `@k2b/ui`) are resolved through imports and do not need discovery roots. Do not scan their examples or test fixtures.\n\n```ts\ncreateConfig({\n  rootDir: workspaceRoot,\n  componentRoots: [\"packages/my-app/src\", frameworkSourceDir],\n});\n```\n\nUse the same configuration in development and production. Files outside `rootDir` retain the existing canonical absolute-path ID fallback; moving an external package can change its IDs. SSR wrappers and browser assets must come from the same build.\n- `basePath` moves SSR assets and dev endpoints under that prefix, e.g. `/docs/_ssr`.\n- Development builds emit linked source maps by default. Use `\"inline\"` only when a tool requires embedded maps, or `\"none\"` to disable them.\n- In production, all modules share a build timestamp directory (`/_ssr/<version>/<id>.js`). Relative lazy imports inherit that directory, so each module has one URL. Files stay flat on disk; adapters serve only the current build version.\n- All adapters stream island assets from `Bun.file`. Production assets under the versioned path and content-hashed development chunks are immutable; stable development entries and source maps use validators for inexpensive freshness checks.\n- Production adapters serve adjacent `.br` or `.gz` files when accepted by the request, preserving the original MIME type and varying caches by `Accept-Encoding`. Generate these siblings in the application build; the adapter does not compress responses at runtime. Development always serves the original file to avoid stale compressed copies.\n\n## Microfrontend mount example\n\nUse `basePath` when the SSR app is mounted under a sub-path:\n\n```ts\n// config.ts\nexport const { config, html } = createConfig({\n  basePath: \"/docs\",\n});\n\n// docs-app.ts\nconst docsApp = new Hono()\n  .route(\"/_ssr\", routes(config))\n  .get(\"/\", () => html(() => <DocsHome />));\n\n// host-app.ts\nexport default new Hono().route(\"/docs\", docsApp);\n```\n\nWith this setup, hydration chunks and dev endpoints are served from `/docs/_ssr/...`.\n\n## Build for production\n\nSet the environment before starting Bun so both the build configuration and bundled code use production mode:\n\n```bash\nNODE_ENV=production bun scripts/build.ts\n```\n\n```ts\n// scripts/build.ts\nimport { plugin } from \"./config\";\n\nawait Bun.build({\n  entrypoints: [\"src/server.tsx\"],\n  outdir: \"dist\",\n  target: \"bun\",\n  plugins: [plugin()],\n});\n```\n\n## Hono `createSSRHandler` behavior\n\n`createSSRHandler(html)` returns an `ssr()` helper that:\n\n- initializes `c.get(\"page\")` as typed page options\n- accepts middlewares/validators before final handler\n- lets handlers return either a synchronous render function or `Response`\n\n## Dev mode tools\n\nWith `dev: true`, a small `[ssr]` overlay is injected.\n\nIt can:\n\n- auto-reload on server restart\n- highlight island/client boundaries\n- show source filenames for wrapped components\n\nIn browsers with Web Locks support, auto-reload elects one visible tab per\norigin and SSR path to hold the SSE connection. Hidden tabs suspend reload work,\nleadership transfers automatically, and cached pages resume safely after a\nback-forward cache restore. Browsers without Web Locks retain visibility-scoped\nper-tab connections as a compatibility fallback.\n\n## Limitations\n\n- islands must use default export\n- props must be serializable via `seroval`; do not pass functions, callbacks, event handlers, Solid signals/stores, DOM nodes, or class instances as island/client props\n- nested island/client imports are not supported\n\n## Local monorepo example\n\nThis repo includes a current example app:\n\n- `packages/ssr-example`\n\nRun from workspace root:\n\n```bash\nbun run dev:example\n```\n","readmeFilename":"README.md"}