From e871e8d44df332bf7af58f48e580133b3dd6f0bc Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 16:30:00 -0400 Subject: [PATCH 01/18] cloudflare --- .../adapter-cloudflare/files/internal.d.ts | 21 ++++++++----- packages/adapter-cloudflare/files/worker.js | 30 +++++++------------ packages/adapter-cloudflare/index.js | 21 +++++-------- 3 files changed, 31 insertions(+), 41 deletions(-) diff --git a/packages/adapter-cloudflare/files/internal.d.ts b/packages/adapter-cloudflare/files/internal.d.ts index 6c79569f7f7f..d3e8d81fe7e8 100644 --- a/packages/adapter-cloudflare/files/internal.d.ts +++ b/packages/adapter-cloudflare/files/internal.d.ts @@ -1,12 +1,17 @@ declare module 'SERVER' { - export { Server } from '@sveltejs/kit'; + export const server: import('@sveltejs/kit').Server; } -declare module 'MANIFEST' { - import { SSRManifest } from '@sveltejs/kit'; - - export const manifest: SSRManifest; - export const prerendered: Set; - export const app_path: string; - export const base_path: string; +namespace Cloudflare { + interface Env { + ASSETS_BINDING: { + fetch: typeof fetch; + }; + [key: string]: string | undefined; + } } + +declare const BASE_PATH: string; +declare const APP_PATH: string; +declare const PRERENDERED: Set; +declare const MANIFEST_ASSETS: Set; diff --git a/packages/adapter-cloudflare/files/worker.js b/packages/adapter-cloudflare/files/worker.js index 911af0cfb971..47b478476762 100644 --- a/packages/adapter-cloudflare/files/worker.js +++ b/packages/adapter-cloudflare/files/worker.js @@ -1,13 +1,12 @@ -import { Server } from 'SERVER'; -import { manifest, prerendered, base_path } from 'MANIFEST'; +import { server } from 'SERVER'; import { env } from 'cloudflare:workers'; -const server = new Server(manifest); +const base_path = BASE_PATH; +const assets = MANIFEST_ASSETS; +const prerendered = PRERENDERED; -const app_path = `/${manifest.appPath}`; - -const immutable = `${app_path}/immutable/`; -const version_file = `${app_path}/version.json`; +const immutable = `/${APP_PATH}/immutable/`; +const version_file = `/${APP_PATH}/version.json`; /** * We don't know the origin until we receive a request, but @@ -17,11 +16,10 @@ const version_file = `${app_path}/version.json`; let origin; const initialized = server.init({ - env: /** @type {Record} */ (env), + env, read: async (file) => { const url = `${origin}/${file}`; - const response = - await /** @type {{ ASSETS: { fetch: typeof fetch } }} */ (env).ASSETS.fetch(url); + const response = await env.ASSETS_BINDING.fetch(url); if (!response.ok) { throw new Error( @@ -33,13 +31,8 @@ const initialized = server.init({ } }); +/** @type {import('@cloudflare/workers-types').ExportedHandler} */ export default { - /** - * @param {Request} req - * @param {{ ASSETS: { fetch: typeof fetch } }} env - * @param {ExecutionContext} ctx - * @returns {Promise} - */ async fetch(req, env, ctx) { if (!origin) { origin = new URL(req.url).origin; @@ -61,8 +54,7 @@ export default { let is_static_asset = false; const filename = stripped_pathname.slice(base_path.length + 1); if (filename) { - is_static_asset = - manifest.assets.has(filename) || manifest.assets.has(filename + '/index.html'); + is_static_asset = assets.has(filename) || assets.has(filename + '/index.html'); } let location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/'; @@ -73,7 +65,7 @@ export default { pathname === version_file || pathname.startsWith(immutable) ) { - let res = await env.ASSETS.fetch(req); + let res = await env.ASSETS_BINDING.fetch(req); // `_headers` applies cache regardless of status, so we need to ensure an // error response does not get cached if (res.status >= 400) { diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index d137538e7194..b4e981f1cf07 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -103,22 +103,15 @@ export default function (options = {}) { // worker const worker_dest_dir = path.dirname(worker_dest); - writeFileSync( - `${tmp}/manifest.js`, - `export const manifest = ${builder.generateManifest({ relativePath: path.posix.relative(tmp, builder.getServerDirectory()) })};\n\n` + - `export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});\n\n` + - `export const base_path = ${JSON.stringify(builder.config.paths.base)};\n` - ); + builder.writeServerEntrypoint(`${tmp}/server.js`); builder.copy(`${files}/worker.js`, worker_dest, { replace: { - // the paths returned by the Wrangler config might be Windows paths, - // so we need to convert them to POSIX paths or else the backslashes - // will be interpreted as escape characters and create an incorrect import path. - // We also need to ensure the relative imports start with ./ since Wrangler - // errors if a relative import looks like a package import - SERVER: `./${posixify(path.relative(worker_dest_dir, builder.getServerDirectory()))}/index.js`, - MANIFEST: `./${posixify(path.relative(worker_dest_dir, tmp))}/manifest.js`, - ASSETS: assets_binding + SERVER: `./${path.posix.relative(worker_dest_dir, tmp)}/index.js`, + BASE_PATH: JSON.stringify(builder.config.paths.base), + APP_PATH: JSON.stringify(builder.getAppPath()), + MANIFEST_ASSETS: `new Set(${JSON.stringify(builder.manifest.assets)})`, + PRERENDERED: `new Set(${JSON.stringify(builder.prerendered.paths)})`, + ASSETS_BINDING: assets_binding } }); if (builder.hasServerInstrumentationFile()) { From 8be8a0dedf4c8e8cd044bb62921de2617c115ca8 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 16:39:20 -0400 Subject: [PATCH 02/18] netlify --- packages/adapter-netlify/files/edge.js | 5 +-- packages/adapter-netlify/files/serverless.js | 7 ++--- packages/adapter-netlify/index.js | 32 ++++++++------------ packages/adapter-netlify/internal.d.ts | 8 +---- 4 files changed, 17 insertions(+), 35 deletions(-) diff --git a/packages/adapter-netlify/files/edge.js b/packages/adapter-netlify/files/edge.js index 518593892b06..b38d8b34e1cd 100644 --- a/packages/adapter-netlify/files/edge.js +++ b/packages/adapter-netlify/files/edge.js @@ -1,7 +1,4 @@ -import { Server } from '0SERVER'; -import { manifest } from 'MANIFEST'; - -const server = new Server(manifest); +import { server } from '0SERVER'; /** * We don't know the origin until we receive a request, but diff --git a/packages/adapter-netlify/files/serverless.js b/packages/adapter-netlify/files/serverless.js index 56502dc95c6c..7397719ef335 100644 --- a/packages/adapter-netlify/files/serverless.js +++ b/packages/adapter-netlify/files/serverless.js @@ -1,14 +1,11 @@ -import { Server } from '0SERVER'; import { createReadableStream } from '@sveltejs/kit/node'; import process from 'node:process'; /** - * @param {import('@sveltejs/kit').SSRManifest} manifest + * @param {import('@sveltejs/kit').Server} server * @returns {(request: Request, context: import('@netlify/types').Context) => Promise} */ -export function init(manifest) { - const server = new Server(manifest); - +export function init(server) { /** @type {Promise | null} */ let init_promise = server.init({ env: process.env, diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index c08cda021813..84bb0ffd6575 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -264,12 +264,11 @@ function write_frameworks_config({ builder }) { * }} opts */ function generate_serverless_function({ builder, routes, patterns, name, type, exclude }) { - const manifest = builder.generateManifest({ - relativePath: '../server', + builder.writeServerEntrypoint(`.netlify/v1/server-${name}.js`, { routes }); - const fn = generate_serverless_function_module(manifest, type); + const fn = generate_serverless_function_module(name, type); const config = generate_config_export(name, patterns, exclude); if (builder.hasServerInstrumentationFile()) { @@ -288,11 +287,11 @@ function generate_serverless_function({ builder, routes, patterns, name, type, e } /** - * @param {string} manifest + * @param {string} name * @param {ServerlessFunctionType} type * @returns {string} */ -function generate_serverless_function_module(manifest, type) { +function generate_serverless_function_module(name, type) { if (type === 'catch-all') { // Netlify encodes the response body but `fetch` automatically decodes it. // So, we need to remove the `content-encoding` header to allow Netlify @@ -300,10 +299,11 @@ function generate_serverless_function_module(manifest, type) { return `\ import { applyReroute } from '@sveltejs/kit/adapter'; import { init } from '../serverless.js'; +import { server } from '../server-${name}.js'; const original_url_header = \`x-sveltekit-original-url-\${process.env.NETLIFY_FUNCTIONS_TOKEN}\` -const respond = init(${manifest}); +const respond = init(server); export default async (request, context) => { const catch_all_response = await respond(request, context); @@ -329,10 +329,11 @@ export default async (request, context) => { if (type === 'split') { return `\ import { init } from '../serverless.js'; +import { server } from '../server-${name}.js'; const original_url_header = \`x-sveltekit-original-url-\${process.env.NETLIFY_FUNCTIONS_TOKEN}\` -const respond = init(${manifest}); +const respond = init(server); export default async (request, context) => { if (request.headers.has(original_url_header)) { @@ -348,8 +349,9 @@ export default async (request, context) => { return `\ import { init } from '../serverless.js'; +import { server } from '../server-${name}.js'; -export default init(${manifest}); +export default init(server); `; } @@ -426,19 +428,11 @@ async function generate_edge_functions({ builder }) { builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, { replace: { - '0SERVER': `${relativePath}/index.js`, - MANIFEST: './manifest.js' + '0SERVER': `./server.js` } }); - const manifest = builder.generateManifest({ - relativePath - }); - - writeFileSync(`${tmp}/manifest.js`, `export const manifest = ${manifest};\n`); - - /** @type {{ assets: Set }} */ - const { assets } = (await import(pathToFileURL(`${tmp}/manifest.js`).href)).manifest; + builder.writeServerEntrypoint(`${tmp}/server.js`); const path = '/*'; // We only need to specify paths without the trailing slash because @@ -449,7 +443,7 @@ async function generate_edge_functions({ builder }) { `/${builder.getAppPath()}/version.json`, // the base root and `trailingSlash: 'always'` pages are recorded with a trailing slash ...builder.prerendered.paths.map((path) => (path === '/' ? path : path.replace(/\/$/, ''))), - ...Array.from(assets).flatMap((asset) => { + ...Array.from(builder.manifest.assets).flatMap((asset) => { if (asset.endsWith('/index.html')) { const dir = asset.replace(/\/index\.html$/, ''); return [`${builder.config.paths.base}/${asset}`, `${builder.config.paths.base}/${dir}`]; diff --git a/packages/adapter-netlify/internal.d.ts b/packages/adapter-netlify/internal.d.ts index 55da8ba1fbf5..97df9e32dfe3 100644 --- a/packages/adapter-netlify/internal.d.ts +++ b/packages/adapter-netlify/internal.d.ts @@ -1,9 +1,3 @@ declare module '0SERVER' { - export { Server } from '@sveltejs/kit'; -} - -declare module 'MANIFEST' { - import { SSRManifest } from '@sveltejs/kit'; - - export const manifest: SSRManifest; + export const server: import('@sveltejs/kit').Server; } From 98038b10d4a01b819bbdbd8df6d3dd27e064615b Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 16:50:17 -0400 Subject: [PATCH 03/18] node --- packages/adapter-node/index.d.ts | 5 ++++ packages/adapter-node/index.js | 44 +++++++++++++++------------- packages/adapter-node/internal.d.ts | 11 +------ packages/adapter-node/src/handler.js | 18 +++++------- 4 files changed, 37 insertions(+), 41 deletions(-) diff --git a/packages/adapter-node/index.d.ts b/packages/adapter-node/index.d.ts index 71daeab1361c..4166b9c9b3ae 100644 --- a/packages/adapter-node/index.d.ts +++ b/packages/adapter-node/index.d.ts @@ -5,6 +5,11 @@ declare global { const ENV_PREFIX: string; const PRECOMPRESS: boolean; const ORIGIN: string | undefined; + const UNCOMPRESSED_EXTENSIONS: Set; + const BASE_PATH: string; + const APP_PATH: string; + const PRERENDERED: Set; + const MIME_TYPES: Record; } interface AdapterOptions { diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index 4ce90cf944c7..b6ec49696af5 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -65,16 +65,6 @@ export default function (opts = {}) { const dir_id = `${entries}/dir.js`; - writeFileSync( - `${server}/manifest.js`, - [ - `export const manifest = ${builder.generateManifest({ relativePath: './' })};`, - `export const prerendered = new Set(${JSON.stringify(builder.prerendered.paths)});`, - `export const base = ${JSON.stringify(builder.config.paths.base)};`, - `export const uncompressed_extensions = new Set(${JSON.stringify([...uncompressed_extensions])});` - ].join('\n\n') - ); - /** @type {Record} */ const input = { index: `${entries}/index.js`, @@ -86,6 +76,20 @@ export default function (opts = {}) { input['instrumentation.server'] = `${server}/instrumentation.server.js`; } + builder.writeServerEntrypoint(`${server}/server.js`); + + /** @type {Record} */ + const defines = { + UNCOMPRESSED_EXTENSIONS: `new Set(${JSON.stringify([...uncompressed_extensions])})`, + BASE_PATH: JSON.stringify(builder.config.paths.base), + APP_PATH: JSON.stringify(builder.getAppPath()), + PRERENDERED: `new Set(${JSON.stringify(builder.prerendered.paths)})`, + MIME_TYPES: JSON.stringify(builder.mimeTypes), + ORIGIN: JSON.stringify(builder.config.paths.origin) || 'undefined', + ENV_PREFIX: JSON.stringify(envPrefix), + PRECOMPRESS: JSON.stringify(precompress) + }; + // we bundle the Vite output so that deployments only need // their production dependencies. Anything in devDependencies // will get included in the bundled code @@ -111,9 +115,11 @@ export default function (opts = {}) { { // resolve the app's server and manifest, generated above name: 'adapter-node-resolve-app', - resolveId(id) { - if (id === 'SERVER') return `${server}/index.js`; - if (id === 'MANIFEST') return `${server}/manifest.js`; + resolveId: { + filter: { id: /^SERVER$/ }, + handler() { + return `${server}/server.js`; + } } }, { @@ -125,13 +131,11 @@ export default function (opts = {}) { filter: { id: new RegExp(escape_regex(entries)) }, handler(_code, _id, { magicString }) { if (!magicString) throw new Error('experimental.nativeMagicString is not enabled'); - magicString - .replace(/\bENV_PREFIX\b/g, JSON.stringify(envPrefix)) - .replace(/\bPRECOMPRESS\b/g, JSON.stringify(precompress)) - .replace( - /\bORIGIN\b/g, - JSON.stringify(builder.config.paths.origin) || 'undefined' - ); + + for (const [from, to] of Object.entries(defines)) { + magicString.replace(new RegExp(`\\b${from}\\b`, 'g'), to); + } + return { code: magicString, map: magicString.generateMap().toString() diff --git a/packages/adapter-node/internal.d.ts b/packages/adapter-node/internal.d.ts index 8748941c8a6f..8897747bd7c3 100644 --- a/packages/adapter-node/internal.d.ts +++ b/packages/adapter-node/internal.d.ts @@ -1,12 +1,3 @@ -declare module 'MANIFEST' { - import { SSRManifest } from '@sveltejs/kit'; - - export const base: string; - export const uncompressed_extensions: Set; - export const manifest: SSRManifest; - export const prerendered: Set; -} - declare module 'SERVER' { - export { Server } from '@sveltejs/kit'; + export const server: import('@sveltejs/kit').Server; } diff --git a/packages/adapter-node/src/handler.js b/packages/adapter-node/src/handler.js index 28ab9d49b650..5aa8920b4402 100644 --- a/packages/adapter-node/src/handler.js +++ b/packages/adapter-node/src/handler.js @@ -6,17 +6,17 @@ import process from 'node:process'; import sirv from 'sirv'; import { parse as polka_url_parser } from '@polka/url'; import { getRequest, setResponse, createReadableStream } from '@sveltejs/kit/node'; -import { Server } from 'SERVER'; -import { manifest, prerendered, base, uncompressed_extensions } from 'MANIFEST'; +import { server } from 'SERVER'; import { dir } from './dir.js'; import { env, env_prefix } from './env.js'; import { parse_as_bytes } from './utils.js'; /** @typedef {(req: IncomingMessage, res: ServerResponse, next: () => void | Promise) => void | Promise} Middleware */ -const server = new Server(manifest); - const origin = ORIGIN; +const uncompressed_extensions = UNCOMPRESSED_EXTENSIONS; +const prerendered = PRERENDERED; +const mime_types = MIME_TYPES; const xff_depth = parseInt(env('XFF_DEPTH', '1')); const address_header = env('ADDRESS_HEADER', '').toLowerCase(); @@ -32,7 +32,7 @@ if (isNaN(body_size_limit)) { ); } -const asset_dir = `${dir}/client${base}`; +const asset_dir = `${dir}/client${BASE_PATH}`; await server.init({ env: process.env, @@ -56,16 +56,12 @@ function serve(path, client = false) { } // `sirv` uses its own bundled `mrmime`, which the manifest's added types never reach - let type = manifest.mimeTypes[pathname.slice(pathname.lastIndexOf('.'))]; + let type = mime_types[pathname.slice(pathname.lastIndexOf('.'))]; if (type === 'text/html') type += ';charset=utf-8'; if (type) res.setHeader('content-type', type); // only apply to build directory, not e.g. version.json - if ( - client && - pathname.startsWith(`/${manifest.appPath}/immutable/`) && - res.statusCode === 200 - ) { + if (client && pathname.startsWith(`/${APP_PATH}/immutable/`) && res.statusCode === 200) { res.setHeader('cache-control', 'public,max-age=31536000,immutable'); } } From c045bcaf84314800d8b4612d68bd188700cce6e3 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 16:51:55 -0400 Subject: [PATCH 04/18] vercel --- .../docs/25-build-and-deploy/99-writing-adapters.md | 4 ++-- packages/adapter-vercel/files/serverless.js | 5 +---- packages/adapter-vercel/index.js | 10 ++-------- packages/adapter-vercel/internal.d.ts | 7 +------ 4 files changed, 6 insertions(+), 20 deletions(-) diff --git a/documentation/docs/25-build-and-deploy/99-writing-adapters.md b/documentation/docs/25-build-and-deploy/99-writing-adapters.md index a4002696a018..02996e7466c8 100644 --- a/documentation/docs/25-build-and-deploy/99-writing-adapters.md +++ b/documentation/docs/25-build-and-deploy/99-writing-adapters.md @@ -60,8 +60,8 @@ Within the `adapt` method, there are a number of things that an adapter should d - Clear out the build directory - Write SvelteKit output with `builder.writeClient`, `builder.writeServer`, and `builder.writePrerendered` - Output code that: - - Imports `Server` from `${builder.getServerDirectory()}/index.js` - - Instantiates the app with a manifest generated with `builder.generateManifest({ relativePath })` + - Imports a `server` instance generated by `${builder.generateServer()}` + - Runs `await server.init({ env, read })` - Listens for requests from the platform, converts them to a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `server.respond(request, { getClientAddress })` function to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it - expose any platform-specific information to SvelteKit via the `platform` option passed to `server.respond` - Bundle the output to avoid needing to install dependencies on the target platform, if necessary diff --git a/packages/adapter-vercel/files/serverless.js b/packages/adapter-vercel/files/serverless.js index d6aa640edf16..8e3bdc096974 100644 --- a/packages/adapter-vercel/files/serverless.js +++ b/packages/adapter-vercel/files/serverless.js @@ -1,10 +1,7 @@ import { createReadableStream } from '@sveltejs/kit/node'; -import { Server } from 'SERVER'; -import { manifest } from 'MANIFEST'; +import { server } from 'SERVER'; import process from 'node:process'; -const server = new Server(manifest); - await server.init({ env: process.env, read: createReadableStream diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 99a7b67c6ec5..137247c51352 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -61,11 +61,9 @@ const plugin = function (defaults = {}) { builder.copy(proxy, entrypoint); } - const relativePath = path.posix.relative(tmp, builder.getServerDirectory()); builder.copy(`${files}/serverless.js`, proxy ? `${tmp}/serverless.js` : entrypoint, { replace: { - SERVER: `${relativePath}/index.js`, - MANIFEST: './manifest.js' + SERVER: `./server.js` } }); if (builder.hasServerInstrumentationFile()) { @@ -74,11 +72,7 @@ const plugin = function (defaults = {}) { instrumentation: `${builder.getServerDirectory()}/instrumentation.server.js` }); } - - write( - `${tmp}/manifest.js`, - `export const manifest = ${builder.generateManifest({ relativePath, routes })};\n` - ); + builder.writeServerEntrypoint(`${tmp}/server.js`, { routes }); await create_function_bundle(builder, entrypoint, dir, config); diff --git a/packages/adapter-vercel/internal.d.ts b/packages/adapter-vercel/internal.d.ts index 537f7cc041d1..8897747bd7c3 100644 --- a/packages/adapter-vercel/internal.d.ts +++ b/packages/adapter-vercel/internal.d.ts @@ -1,8 +1,3 @@ declare module 'SERVER' { - export { Server } from '@sveltejs/kit'; -} - -declare module 'MANIFEST' { - import { SSRManifest } from '@sveltejs/kit'; - export const manifest: SSRManifest; + export const server: import('@sveltejs/kit').Server; } From 28735dabaea11904b7090ed073a37fc78186ab29 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 17:24:49 -0400 Subject: [PATCH 05/18] breaking: replace the `generateManifest` adapter api with `writeServerEntrypoint` and `builder.manifest` --- .changeset/smooth-flies-begin.md | 10 ++++ packages/adapter-netlify/index.js | 7 +-- packages/kit/src/core/adapt/builder.js | 59 +++++++++++++------ packages/kit/src/core/adapt/index.js | 3 + .../kit/src/core/sync/write_app_manifest.js | 5 +- packages/kit/src/exports/public.d.ts | 18 +++++- packages/kit/src/exports/vite/build/index.js | 19 ++++-- .../kit/src/exports/vite/preview/index.js | 1 + packages/kit/types/index.d.ts | 17 +++++- 9 files changed, 107 insertions(+), 32 deletions(-) create mode 100644 .changeset/smooth-flies-begin.md diff --git a/.changeset/smooth-flies-begin.md b/.changeset/smooth-flies-begin.md new file mode 100644 index 000000000000..da2f9b58f3e1 --- /dev/null +++ b/.changeset/smooth-flies-begin.md @@ -0,0 +1,10 @@ +--- +"@sveltejs/adapter-cloudflare": major +"@sveltejs/adapter-netlify": major +"@sveltejs/adapter-node": major +"@sveltejs/adapter-vercel": major +"@sveltejs/kit": major +--- + +breaking: replace the `generateManifest` adapter api with `writeServerEntrypoint` and `builder.manifest` + \ No newline at end of file diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 84bb0ffd6575..f780c2fab4f2 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -1,6 +1,6 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; -import { join, posix } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; +import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { builtinModules } from 'node:module'; import process from 'node:process'; import toml from '@iarna/toml'; @@ -424,7 +424,6 @@ async function generate_edge_functions({ builder }) { mkdirSync('.netlify/v1/edge-functions', { recursive: true }); builder.log.minor('Generating Edge Function...'); - const relativePath = posix.relative(tmp, builder.getServerDirectory()); builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, { replace: { @@ -443,7 +442,7 @@ async function generate_edge_functions({ builder }) { `/${builder.getAppPath()}/version.json`, // the base root and `trailingSlash: 'always'` pages are recorded with a trailing slash ...builder.prerendered.paths.map((path) => (path === '/' ? path : path.replace(/\/$/, ''))), - ...Array.from(builder.manifest.assets).flatMap((asset) => { + ...Array.from(builder.manifest.assets).flatMap(({ path: asset }) => { if (asset.endsWith('/index.html')) { const dir = asset.replace(/\/index\.html$/, ''); return [`${builder.config.paths.base}/${asset}`, `${builder.config.paths.base}/${dir}`]; diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index 5be5e91482bd..cf02857a0327 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -13,7 +13,7 @@ import { rmSync, statSync } from 'node:fs'; -import { extname, resolve, join, dirname, relative } from 'node:path'; +import path from 'node:path'; import { pipeline } from 'node:stream'; import { promisify } from 'node:util'; import zlib from 'node:zlib'; @@ -22,10 +22,11 @@ import { posixify } from '../../utils/os.js'; import { generate_manifest } from '../generate_manifest/index.js'; import { get_route_segments } from '../../utils/routing.js'; import generate_fallback from '../postbuild/fallback.js'; -import { write } from '../sync/utils.js'; +import { dedent, write } from '../sync/utils.js'; import { find_server_assets } from '../generate_manifest/find_server_assets.js'; import { create_exported_declarations } from '../env.js'; import { handle_issues, validate } from '../../exports/internal/env.js'; +import { get_mime_lookup } from '../utils.js'; const pipe = promisify(pipeline); const extensions = [ @@ -51,6 +52,7 @@ const extensions = [ * route_data: RouteData[]; * prerendered: Prerendered; * prerender_map: PrerenderMap; + * app_manifest: typeof import('$app/manifest'); * log: Logger; * vite_config: ResolvedConfig; * remotes: RemoteChunk[]; @@ -65,6 +67,7 @@ export function create_builder({ route_data, prerendered, prerender_map, + app_manifest, log, vite_config, remotes, @@ -112,17 +115,21 @@ export function create_builder({ config, prerendered, routes, + manifest: app_manifest, + get mimeTypes() { + return get_mime_lookup(build_data.manifest_data); + }, async compress(directory) { if (!existsSync(directory)) { return []; } - const files = [...walk(directory)].filter((file) => extensions.includes(extname(file))); + const files = [...walk(directory)].filter((file) => extensions.includes(path.extname(file))); await Promise.all( files.flatMap((file) => { - const abs = resolve(directory, file); + const abs = path.resolve(directory, file); return [compress_file(abs, 'gz'), compress_file(abs, 'br')]; }) ); @@ -184,17 +191,31 @@ export function create_builder({ write(`${dest}/env.js`, `export const env=${payload}`); }, - generateManifest({ relativePath, routes: subset }) { - return generate_manifest({ - build_data, - prerendered: prerendered.paths, - relative_path: relativePath, - routes: subset - ? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route))) - : route_data.filter((route) => prerender_map.get(route.id) !== true), - remotes, - root: vite_config.root - }); + generateManifest() { + throw new Error( + `The \`generateManifest\` adapter API is deprecated — it has been replaced with \`writeServerEntrypoint\` and \`getManifest\`. You may need to update your adapter` + ); + }, + + writeServerEntrypoint(dest, { routes: subset } = {}) { + const relativePath = path.posix.relative(path.dirname(dest), this.getServerDirectory()); + write( + dest, + dedent` + import { Server } from '${relativePath}/index.js'; + const manifest = ${generate_manifest({ + build_data, + prerendered: prerendered.paths, + relative_path: relativePath, + routes: subset + ? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route))) + : route_data.filter((route) => prerender_map.get(route.id) !== true), + remotes, + root: vite_config.root + })}; + export const server = new Server(manifest); + ` + ); }, getBuildDirectory(name) { @@ -241,7 +262,7 @@ export function create_builder({ instrument({ entrypoint, instrumentation, - start = join(dirname(entrypoint), 'start.js'), + start = path.join(path.dirname(entrypoint), 'start.js'), module = { exports: ['default'] } @@ -262,8 +283,10 @@ export function create_builder({ copy(`${entrypoint}.map`, `${start}.map`); } - const relative_instrumentation = posixify(relative(dirname(entrypoint), instrumentation)); - const relative_start = posixify(relative(dirname(entrypoint), start)); + const relative_instrumentation = posixify( + path.relative(path.dirname(entrypoint), instrumentation) + ); + const relative_start = posixify(path.relative(path.dirname(entrypoint), start)); const facade = 'generateText' in module diff --git a/packages/kit/src/core/adapt/index.js b/packages/kit/src/core/adapt/index.js index 46f1fd5bc640..7b6c0850a26a 100644 --- a/packages/kit/src/core/adapt/index.js +++ b/packages/kit/src/core/adapt/index.js @@ -7,6 +7,7 @@ import { create_builder } from './builder.js'; * @param {import('types').ServerMetadata} server_metadata * @param {import('types').Prerendered} prerendered * @param {import('types').PrerenderMap} prerender_map + * @param {typeof import('$app/manifest')} app_manifest * @param {import('types').Logger} log * @param {import('types').RemoteChunk[]} remotes * @param {import('vite').ResolvedConfig} vite_config @@ -18,6 +19,7 @@ export async function adapt( server_metadata, prerendered, prerender_map, + app_manifest, log, remotes, vite_config, @@ -48,6 +50,7 @@ export async function adapt( route_data: build_data.manifest_data.routes.filter((route) => route.page || route.endpoint), prerendered, prerender_map, + app_manifest, log, remotes, vite_config, diff --git a/packages/kit/src/core/sync/write_app_manifest.js b/packages/kit/src/core/sync/write_app_manifest.js index 8a0fe6b07b18..3a16fb5c2495 100644 --- a/packages/kit/src/core/sync/write_app_manifest.js +++ b/packages/kit/src/core/sync/write_app_manifest.js @@ -1,4 +1,5 @@ /** @import { Asset, ManifestData, RouteData } from 'types' */ +/** @import { ManifestRoute } from '$app/manifest' */ import { s } from '../../utils/misc.js'; import { is_app_route, is_endpoint_route, is_page_route } from './create_manifest_data/index.js'; @@ -60,11 +61,11 @@ function stringify_assets(assets) { /** * @param {RouteData[] | undefined} routes - * @returns {Array<{ id: string; page: boolean; endpoint: boolean }>} + * @returns {ManifestRoute[]} */ export function get_manifest_routes(routes) { return ( - routes?.filter(is_app_route).map((route) => ({ + routes?.filter(is_app_route).map((route) => /** @type {ManifestRoute} */ ({ id: route.id, page: is_page_route(route), endpoint: is_endpoint_route(route) diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 8fde64196aeb..dfddcad02a01 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -139,6 +139,10 @@ export interface Builder { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; + /** The value of the `$app/manifest` module */ + manifest: typeof import('$app/manifest'); + /** */ + mimeTypes: Record; /** * Create separate functions that map to one or more routes of your app. @@ -166,8 +170,9 @@ export interface Builder { * Generate a server-side manifest to initialise the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) with. * @param opts * @param opts.relativePath A relative path to the base directory of the server build output + * @deprecated removed in 3.0. Use `builder.writeServerEntrypoint` or `builder.manifest` instead */ - generateManifest: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; + generateManifest?: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; /** * Resolve a path to the `name` directory inside `outDir`, e.g. `/path/to/.svelte-kit/my-adapter`. @@ -181,6 +186,17 @@ export interface Builder { /** Get the application path including any configured `base` path, e.g. `my-base-path/_app`. */ getAppPath: () => string; + /** + * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). + * @param dest + * @param opts.routes A subset of the routes to include in the server's manifest + */ + writeServerEntrypoint: ( + dest: string, + opts?: { + routes?: RouteDefinition[]; + } + ) => void; /** * Write client assets to `dest`. * @param dest the destination folder diff --git a/packages/kit/src/exports/vite/build/index.js b/packages/kit/src/exports/vite/build/index.js index 84b850a50702..db7686ac2de7 100644 --- a/packages/kit/src/exports/vite/build/index.js +++ b/packages/kit/src/exports/vite/build/index.js @@ -862,6 +862,14 @@ export function plugin_compile( // defer until after other buildApp hooks have run finalise = async () => { + /** @type {typeof import('$app/manifest')} */ + const app_manifest = { + assets: manifest_data.assets.map((asset) => ({ path: asset.file })), + immutable: immutable ?? [], + prerendered: prerendered_paths, + routes: get_manifest_routes(manifest_data.routes) + }; + // defer creating the service worker to avoid other plugins from // overwriting it if they run a client environment build if (service_worker_entry_file) { @@ -871,12 +879,10 @@ export function plugin_compile( builder.environments.serviceWorker.config.define = { ...builder.environments.serviceWorker.config.define, - __SVELTEKIT_MANIFEST_ASSETS__: s( - manifest_data.assets.map((asset) => ({ path: asset.file })) - ), - __SVELTEKIT_MANIFEST_IMMUTABLE__: s(immutable), - __SVELTEKIT_MANIFEST_PRERENDERED__: s(prerendered_paths), - __SVELTEKIT_MANIFEST_ROUTES__: s(get_manifest_routes(manifest_data.routes)) + __SVELTEKIT_MANIFEST_ASSETS__: s(app_manifest.assets), + __SVELTEKIT_MANIFEST_IMMUTABLE__: s(app_manifest.immutable), + __SVELTEKIT_MANIFEST_PRERENDERED__: s(app_manifest.prerendered), + __SVELTEKIT_MANIFEST_ROUTES__: s(app_manifest.routes) }; // we have to overwrite this because it can't be configured per environment in the config hook @@ -905,6 +911,7 @@ export function plugin_compile( metadata, prerendered, prerender_results.prerender_map, + app_manifest, log, remotes, vite_config, diff --git a/packages/kit/src/exports/vite/preview/index.js b/packages/kit/src/exports/vite/preview/index.js index 2c29442c6032..4e0187c9e1b7 100644 --- a/packages/kit/src/exports/vite/preview/index.js +++ b/packages/kit/src/exports/vite/preview/index.js @@ -43,6 +43,7 @@ export async function preview(vite, svelte_config) { /** @type {ServerModule} */ const { Server } = await import(pathToFileURL(join(dir, 'index.js')).href); + /** @type {{ manifest: import('@sveltejs/kit').SSRManifest }} */ const { manifest } = await import(pathToFileURL(join(dir, 'manifest.js')).href); set_assets(assets); diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 09c909a2a620..2a3683b49f09 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -125,6 +125,10 @@ declare module '@sveltejs/kit' { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; + /** The value of the `$app/manifest` module */ + manifest: typeof import('$app/manifest'); + + mimeTypes: Record; /** * Create separate functions that map to one or more routes of your app. @@ -151,8 +155,9 @@ declare module '@sveltejs/kit' { /** * Generate a server-side manifest to initialise the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) with. * @param opts.relativePath A relative path to the base directory of the server build output + * @deprecated removed in 3.0. Use `builder.writeServerEntrypoint` or `builder.manifest` instead */ - generateManifest: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; + generateManifest?: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; /** * Resolve a path to the `name` directory inside `outDir`, e.g. `/path/to/.svelte-kit/my-adapter`. @@ -166,6 +171,16 @@ declare module '@sveltejs/kit' { /** Get the application path including any configured `base` path, e.g. `my-base-path/_app`. */ getAppPath: () => string; + /** + * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). + * @param opts.routes A subset of the routes to include in the server's manifest + */ + writeServerEntrypoint: ( + dest: string, + opts?: { + routes?: RouteDefinition[]; + } + ) => void; /** * Write client assets to `dest`. * @param dest the destination folder From ee198f130b181994fde9d71f45d29972171c020c Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 17:42:31 -0400 Subject: [PATCH 06/18] fix cloudflare --- packages/adapter-cloudflare/index.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index b4e981f1cf07..f31a807ebedb 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -106,10 +106,10 @@ export default function (options = {}) { builder.writeServerEntrypoint(`${tmp}/server.js`); builder.copy(`${files}/worker.js`, worker_dest, { replace: { - SERVER: `./${path.posix.relative(worker_dest_dir, tmp)}/index.js`, + SERVER: `./${path.posix.relative(worker_dest_dir, tmp)}/server.js`, BASE_PATH: JSON.stringify(builder.config.paths.base), APP_PATH: JSON.stringify(builder.getAppPath()), - MANIFEST_ASSETS: `new Set(${JSON.stringify(builder.manifest.assets)})`, + MANIFEST_ASSETS: `new Set(${JSON.stringify(builder.manifest.assets.map((a) => a.path))})`, PRERENDERED: `new Set(${JSON.stringify(builder.prerendered.paths)})`, ASSETS_BINDING: assets_binding } @@ -283,8 +283,3 @@ function validate_wrangler_config(config_file = undefined) { building_for_cloudflare_pages }; } - -/** @param {string} str */ -function posixify(str) { - return str.replace(/\\/g, '/'); -} From d5b19f94f5629dddaa7917a55c3629555ccc3175 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 17:45:35 -0400 Subject: [PATCH 07/18] unused --- packages/adapter-node/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index b6ec49696af5..08dea8b74eb7 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -1,4 +1,4 @@ -import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdirSync, readFileSync, rmSync } from 'node:fs'; import { extname } from 'node:path'; import { fileURLToPath } from 'node:url'; import { rolldown } from 'rolldown'; From f763ab03521d6e7a26aadb6c114bc7aec1bdec75 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Thu, 20 Aug 2026 20:20:15 -0400 Subject: [PATCH 08/18] address most of suggestions --- .../99-writing-adapters.md | 2 +- packages/adapter-cloudflare/index.js | 12 +++++- packages/adapter-netlify/index.js | 3 +- packages/adapter-node/index.js | 4 +- packages/kit/src/core/adapt/builder.js | 38 +++++++++++++++---- .../kit/src/core/generate_manifest/index.js | 6 +-- packages/kit/src/exports/public.d.ts | 4 +- packages/kit/types/index.d.ts | 4 +- 8 files changed, 57 insertions(+), 16 deletions(-) diff --git a/documentation/docs/25-build-and-deploy/99-writing-adapters.md b/documentation/docs/25-build-and-deploy/99-writing-adapters.md index 02996e7466c8..c788a6571125 100644 --- a/documentation/docs/25-build-and-deploy/99-writing-adapters.md +++ b/documentation/docs/25-build-and-deploy/99-writing-adapters.md @@ -60,7 +60,7 @@ Within the `adapt` method, there are a number of things that an adapter should d - Clear out the build directory - Write SvelteKit output with `builder.writeClient`, `builder.writeServer`, and `builder.writePrerendered` - Output code that: - - Imports a `server` instance generated by `${builder.generateServer()}` + - Imports a `server` instance generated by `${builder.writeServerEntrypoint()}` - Runs `await server.init({ env, read })` - Listens for requests from the platform, converts them to a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `server.respond(request, { getClientAddress })` function to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it - expose any platform-specific information to SvelteKit via the `platform` option passed to `server.respond` diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index f31a807ebedb..cc81b4c6b32e 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -106,7 +106,12 @@ export default function (options = {}) { builder.writeServerEntrypoint(`${tmp}/server.js`); builder.copy(`${files}/worker.js`, worker_dest, { replace: { - SERVER: `./${path.posix.relative(worker_dest_dir, tmp)}/server.js`, + // the paths returned by the Wrangler config might be Windows paths, + // so we need to convert them to POSIX paths or else the backslashes + // will be interpreted as escape characters and create an incorrect import path. + // We also need to ensure the relative imports start with ./ since Wrangler + // errors if a relative import looks like a package import + SERVER: `./${posixify(path.relative(worker_dest_dir, tmp))}/server.js`, BASE_PATH: JSON.stringify(builder.config.paths.base), APP_PATH: JSON.stringify(builder.getAppPath()), MANIFEST_ASSETS: `new Set(${JSON.stringify(builder.manifest.assets.map((a) => a.path))})`, @@ -283,3 +288,8 @@ function validate_wrangler_config(config_file = undefined) { building_for_cloudflare_pages }; } + +/** @param {string} str */ +function posixify(str) { + return str.replace(/\\/g, '/'); +} diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index f780c2fab4f2..2c52b27be6e2 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -265,7 +265,8 @@ function write_frameworks_config({ builder }) { */ function generate_serverless_function({ builder, routes, patterns, name, type, exclude }) { builder.writeServerEntrypoint(`.netlify/v1/server-${name}.js`, { - routes + routes, + serverDirectory: '.netlify/v1/server' }); const fn = generate_serverless_function_module(name, type); diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index 08dea8b74eb7..bf8c7db95494 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -133,7 +133,9 @@ export default function (opts = {}) { if (!magicString) throw new Error('experimental.nativeMagicString is not enabled'); for (const [from, to] of Object.entries(defines)) { - magicString.replace(new RegExp(`\\b${from}\\b`, 'g'), to); + // remove $& and $N substitutions by replacing every $ with $$ + const value = to.replace(/\$/g, '$$$$'); + magicString.replace(new RegExp(`\\b${from}\\b`, 'g'), value); } return { diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index cf02857a0327..12a290f5b3ff 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -17,7 +17,7 @@ import path from 'node:path'; import { pipeline } from 'node:stream'; import { promisify } from 'node:util'; import zlib from 'node:zlib'; -import { copy, walk } from '../../utils/filesystem.js'; +import { copy, relative_path, walk } from '../../utils/filesystem.js'; import { posixify } from '../../utils/os.js'; import { generate_manifest } from '../generate_manifest/index.js'; import { get_route_segments } from '../../utils/routing.js'; @@ -27,6 +27,7 @@ import { find_server_assets } from '../generate_manifest/find_server_assets.js'; import { create_exported_declarations } from '../env.js'; import { handle_issues, validate } from '../../exports/internal/env.js'; import { get_mime_lookup } from '../utils.js'; +import { lookup as mime_lookup } from '../../utils/mime.js'; const pipe = promisify(pipeline); const extensions = [ @@ -117,7 +118,27 @@ export function create_builder({ routes, manifest: app_manifest, get mimeTypes() { - return get_mime_lookup(build_data.manifest_data); + const mime_types = get_mime_lookup(build_data.manifest_data); + const server_assets = find_server_assets( + build_data, + route_data.filter((route) => prerender_map.get(route.id) !== true), + vite_config.root + ); + /** @type {Record} */ + const files = {}; + for (const file of server_assets) { + files[file] = statSync(path.resolve(build_data.out_dir, 'server', file)).size; + + const ext = path.extname(file); + mime_types[ext] ??= mime_lookup(ext) || ''; + } + + // record extensions that only exist in prerendered output, e.g. a prerendered favicon.ico + for (const pathname of prerendered.paths) { + const ext = path.extname(pathname); + if (ext) mime_types[ext] ??= mime_lookup(ext) || ''; + } + return mime_types; }, async compress(directory) { @@ -193,20 +214,23 @@ export function create_builder({ generateManifest() { throw new Error( - `The \`generateManifest\` adapter API is deprecated — it has been replaced with \`writeServerEntrypoint\` and \`getManifest\`. You may need to update your adapter` + `The \`generateManifest\` adapter API is deprecated — it has been replaced with \`writeServerEntrypoint\` and \`builder.manifest\`. You may need to update your adapter` ); }, - writeServerEntrypoint(dest, { routes: subset } = {}) { - const relativePath = path.posix.relative(path.dirname(dest), this.getServerDirectory()); + writeServerEntrypoint(dest, { routes: subset, serverDirectory } = {}) { + const relative = relative_path( + path.dirname(dest), + serverDirectory ?? this.getServerDirectory() + ); write( dest, dedent` - import { Server } from '${relativePath}/index.js'; + import { Server } from '${relative}/index.js'; const manifest = ${generate_manifest({ build_data, prerendered: prerendered.paths, - relative_path: relativePath, + relative_path: relative, routes: subset ? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route))) : route_data.filter((route) => prerender_map.get(route.id) !== true), diff --git a/packages/kit/src/core/generate_manifest/index.js b/packages/kit/src/core/generate_manifest/index.js index f524e1da70d2..9edced21991d 100644 --- a/packages/kit/src/core/generate_manifest/index.js +++ b/packages/kit/src/core/generate_manifest/index.js @@ -1,4 +1,4 @@ -/** @import { RemoteChunk } from 'types' */ +/** @import { BuildData, RemoteChunk, RouteData } from 'types' */ import fs from 'node:fs'; import path from 'node:path'; import { lookup as mime_lookup } from '../../utils/mime.js'; @@ -15,10 +15,10 @@ import { uneval } from 'devalue'; * Generates the data used to write the server-side manifest.js file. This data is used in the Vite * build process, to power routing, etc. * @param {{ - * build_data: import('types').BuildData; + * build_data: BuildData; * prerendered: string[]; * relative_path: string; - * routes: import('types').RouteData[]; + * routes: RouteData[]; * remotes: RemoteChunk[]; * root: string; * }} opts diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index dfddcad02a01..6fff2dd40cb0 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -141,7 +141,7 @@ export interface Builder { routes: RouteDefinition[]; /** The value of the `$app/manifest` module */ manifest: typeof import('$app/manifest'); - /** */ + /** A record of file extensions to MIME types */ mimeTypes: Record; /** @@ -190,11 +190,13 @@ export interface Builder { * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). * @param dest * @param opts.routes A subset of the routes to include in the server's manifest + * @param opts.serverDirectory The directory containing the server code. Defaults to `getServerDirectory()`. */ writeServerEntrypoint: ( dest: string, opts?: { routes?: RouteDefinition[]; + serverDirectory?: string; } ) => void; /** diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 2a3683b49f09..2f81cb25970b 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -127,7 +127,7 @@ declare module '@sveltejs/kit' { routes: RouteDefinition[]; /** The value of the `$app/manifest` module */ manifest: typeof import('$app/manifest'); - + /** A record of file extensions to MIME types */ mimeTypes: Record; /** @@ -174,11 +174,13 @@ declare module '@sveltejs/kit' { /** * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). * @param opts.routes A subset of the routes to include in the server's manifest + * @param opts.serverDirectory The directory containing the server code. Defaults to `getServerDirectory()`. */ writeServerEntrypoint: ( dest: string, opts?: { routes?: RouteDefinition[]; + serverDirectory?: string; } ) => void; /** From 3de9458fb344959ccd022cba6a9514f0fc5b09f0 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Fri, 21 Aug 2026 22:21:30 -0400 Subject: [PATCH 09/18] bun :( --- packages/adapter-bun/index.js | 8 ++++++-- packages/adapter-bun/internal.d.ts | 4 ++-- packages/adapter-bun/src/handler.js | 6 ++---- packages/adapter-bun/src/routes-util.js | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/adapter-bun/index.js b/packages/adapter-bun/index.js index abb7579f3f57..d5d4d71ec120 100644 --- a/packages/adapter-bun/index.js +++ b/packages/adapter-bun/index.js @@ -136,9 +136,13 @@ export default function (opts = {}) { const manifest_file = path.resolve(server, 'manifest.js'); const server_options_file = path.resolve(src_dir, 'options.js'); + const tmp = builder.getBuildDirectory('bun-tmp'); + fs.mkdirSync(tmp, { recursive: true }); + builder.writeServerEntrypoint(`${tmp}/server.js`); + const virtual_files = { [manifest_file]: - `export const manifest = ${builder.generateManifest({ relativePath: './' })};\n` + + `export const app_dir = ${JSON.stringify(builder.getAppPath())};\n` + `export const base = ${JSON.stringify(builder.config.paths.base || '/')};\n` + `export const embed = ${JSON.stringify(!!buildOptions.compile)};\n` + `export const env_prefix = ${JSON.stringify(envPrefix)};\n` + @@ -198,7 +202,7 @@ export default function (opts = {}) { name: 'adapter-bun', setup(build) { build.onResolve({ filter: /^(SERVER|MANIFEST|ROUTES|SERVER_OPTIONS)$/ }, ({ path }) => { - if (path === 'SERVER') return { path: `${server}/index.js` }; + if (path === 'SERVER') return { path: `${tmp}/server.js` }; if (path === 'MANIFEST') return { path: manifest_file }; if (path === 'ROUTES') return { path: routes_file }; if (path === 'SERVER_OPTIONS') return { path: server_options_file }; diff --git a/packages/adapter-bun/internal.d.ts b/packages/adapter-bun/internal.d.ts index b3e0ceed137a..ce532903b579 100644 --- a/packages/adapter-bun/internal.d.ts +++ b/packages/adapter-bun/internal.d.ts @@ -1,5 +1,5 @@ declare module 'MANIFEST' { - export const manifest: import('@sveltejs/kit').SSRManifest; + export const app_dir: string; export const base: string; export const embed: boolean; export const env_prefix: string; @@ -12,7 +12,7 @@ declare module 'ROUTES' { } declare module 'SERVER' { - export { Server } from '@sveltejs/kit'; + export const server: import('@sveltejs/kit').Server; } declare module 'SERVER_OPTIONS' { diff --git a/packages/adapter-bun/src/handler.js b/packages/adapter-bun/src/handler.js index d773849f2d56..6fa5d8c9a18a 100644 --- a/packages/adapter-bun/src/handler.js +++ b/packages/adapter-bun/src/handler.js @@ -1,11 +1,9 @@ /** @import { Server as BunServer } from 'bun' */ -import { Server } from 'SERVER'; -import { manifest, origin, env_prefix } from 'MANIFEST'; +import { server } from 'SERVER'; +import { origin, env_prefix } from 'MANIFEST'; import { server_assets } from 'ROUTES'; import { env, number_env } from './env.js'; -const server = new Server(manifest); - const address_header = env('ADDRESS_HEADER', '').toLowerCase(); const protocol_header = env('PROTOCOL_HEADER', '').toLowerCase(); const host_header = env('HOST_HEADER', '').toLowerCase(); diff --git a/packages/adapter-bun/src/routes-util.js b/packages/adapter-bun/src/routes-util.js index 942165cbdc13..3017e26a38f1 100644 --- a/packages/adapter-bun/src/routes-util.js +++ b/packages/adapter-bun/src/routes-util.js @@ -1,5 +1,5 @@ /** @import { BunFile, BunRequest, Serve } from 'bun' */ -import { manifest, base, embed } from 'MANIFEST'; +import { app_dir, base, embed } from 'MANIFEST'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -174,7 +174,7 @@ function file_route(file, meta, extra_headers = {}) { * @returns {Array<[string, RouteHandler]>} */ export function client_asset(url, filename = url, meta) { - const immutable = url.startsWith(`${manifest.appDir}/immutable/`); + const immutable = url.startsWith(`${app_dir}/immutable/`); const route = file_route( resolve_file('client', filename), meta, From 1e6d33a616aee91f5615b87a2c461cda429c3f18 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Sun, 23 Aug 2026 18:44:47 -0700 Subject: [PATCH 10/18] fix bun tests --- packages/adapter-bun/test/adapter.spec.ts | 11 ++++++++--- packages/adapter-bun/test/handler.spec.ts | 12 ++---------- packages/adapter-bun/test/mocks.ts | 6 +++--- packages/adapter-bun/test/routes.spec.ts | 6 +++--- 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/adapter-bun/test/adapter.spec.ts b/packages/adapter-bun/test/adapter.spec.ts index a5963fa9f94f..34c514151ac5 100644 --- a/packages/adapter-bun/test/adapter.spec.ts +++ b/packages/adapter-bun/test/adapter.spec.ts @@ -121,7 +121,7 @@ describe('Bun build configuration', () => { const files = bun_build.mock.calls[0][0].files; expect(files[manifest_file]).toBe( - 'export const manifest = {"appDir":"_app"};\n' + + 'export const app_dir = "/docs/_app";\n' + 'export const base = "/docs";\n' + 'export const embed = false;\n' + 'export const env_prefix = "APP_";\n' + @@ -130,7 +130,9 @@ describe('Bun build configuration', () => { expect(files[options_file]).toBe( 'export default {"hostname":"127.0.0.1","port":4000,"development":true};' ); - expect(builder.generateManifest).toHaveBeenCalledWith({ relativePath: './' }); + expect(builder.writeServerEntrypoint).toHaveBeenCalledWith( + '.svelte-kit/output/bun-tmp/server.js' + ); }); test('resolves generated runtime modules through the Bun plugin', async () => { @@ -144,7 +146,7 @@ describe('Bun build configuration', () => { ); const resolve_module = on_resolve.mock.calls[0][1]; expect(resolve_module({ path: 'SERVER' })).toEqual({ - path: '.svelte-kit/output/server/index.js' + path: '.svelte-kit/output/bun-tmp/server.js' }); expect(resolve_module({ path: 'MANIFEST' })).toEqual({ path: manifest_file }); expect(resolve_module({ path: 'ROUTES' })).toEqual({ path: routes_file }); @@ -588,6 +590,9 @@ function create_builder({ warn: mock((_message: string) => {}), info: mock((_message: string) => {}) }, + getAppPath: () => `${base}/_app`, + writeServerEntrypoint: mock(() => {}), + getBuildDirectory: (dir: string) => `.svelte-kit/output/${dir}`, getServerDirectory: () => '.svelte-kit/output/server', writeClient: mock(() => client_files), writePrerendered: mock(() => prerendered_files), diff --git a/packages/adapter-bun/test/handler.spec.ts b/packages/adapter-bun/test/handler.spec.ts index bc1bd272827f..7735ede19973 100644 --- a/packages/adapter-bun/test/handler.spec.ts +++ b/packages/adapter-bun/test/handler.spec.ts @@ -14,7 +14,6 @@ afterEach(() => { test('initializes SvelteKit with Bun environment variables and server-readable assets', async () => { const loaded = await load_handler(); - expect(loaded.construct).toHaveBeenCalledWith(loaded.manifest); expect(loaded.init).toHaveBeenCalledWith({ env: Bun.env, read: expect.any(Function) @@ -196,23 +195,18 @@ async function load_handler({ envPrefix = '', response = new Response('ok') }: { origin?: string; envPrefix?: string; response?: Response } = {}) { - const manifest = { appDir: '_app' }; const stream = new ReadableStream(); const asset = { stream: mock(() => stream) }; - const construct = mock((_value: unknown) => {}); const init = mock(async (_options: any) => {}); const respond = mock(async (_request: Request, _options: any) => response); class Server { - constructor(value: unknown) { - construct(value); - } init = init; respond = respond; } - mock.module('SERVER', () => ({ Server })); - mock_manifest({ manifest, origin, env_prefix: envPrefix }); + mock.module('SERVER', () => ({ server: new Server() })); + mock_manifest({ app_dir: '_app', origin, env_prefix: envPrefix }); mock_routes({ server_assets: new Map([['asset.txt', asset]]) }); const request_ip = mock((_request: Request): any => ({ @@ -227,9 +221,7 @@ async function load_handler({ return { handler, - manifest, stream, - construct, init, respond, request_ip, diff --git a/packages/adapter-bun/test/mocks.ts b/packages/adapter-bun/test/mocks.ts index 150e00cbd4d4..d1366ccad4b3 100644 --- a/packages/adapter-bun/test/mocks.ts +++ b/packages/adapter-bun/test/mocks.ts @@ -5,19 +5,19 @@ import { mock } from 'bun:test'; // exports that src modules pull from these build-generated specifiers export function mock_manifest({ - manifest, + app_dir, base, embed, origin, env_prefix = '' }: { - manifest?: unknown; + app_dir?: string; base?: string; embed?: boolean; origin?: string; env_prefix?: string; } = {}) { - mock.module('MANIFEST', () => ({ manifest, base, embed, origin, env_prefix })); + mock.module('MANIFEST', () => ({ app_dir, base, embed, origin, env_prefix })); } export function mock_routes({ diff --git a/packages/adapter-bun/test/routes.spec.ts b/packages/adapter-bun/test/routes.spec.ts index 1c736217457c..23fbc87a94c0 100644 --- a/packages/adapter-bun/test/routes.spec.ts +++ b/packages/adapter-bun/test/routes.spec.ts @@ -78,7 +78,7 @@ test('a root deployment registers routes with a leading slash', async () => { }); test('immutable SvelteKit assets receive a long-lived cache policy', async () => { - const { routes } = await load_routes({ appDir: '_app' }); + const { routes } = await load_routes({ app_dir: '_app' }); const request = new Request('http://localhost/'); const immutable = ( @@ -283,8 +283,8 @@ test('prerendered redirects retain their status and location', async () => { expect((handler as any).GET.headers.get('location')).toBe('/new'); }); -async function load_routes({ base = '/', embed = false, appDir = '_app' } = {}) { - mock_manifest({ manifest: { appDir }, base, embed }); +async function load_routes({ base = '/', embed = false, app_dir = '_app' } = {}) { + mock_manifest({ app_dir, base, embed }); // the real Bun.file runs, with the spy recording resolved paths; the files it // points at need not exist because nothing reads their contents const file = spyOn(Bun, 'file'); From 96bc0dd3bdb919bc6d9f74cfb4af68c8ea9565a6 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Sun, 23 Aug 2026 19:00:35 -0700 Subject: [PATCH 11/18] fix bun again --- packages/adapter-bun/index.js | 2 +- packages/adapter-bun/test/adapter.spec.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/adapter-bun/index.js b/packages/adapter-bun/index.js index d5d4d71ec120..0cc2ede1059f 100644 --- a/packages/adapter-bun/index.js +++ b/packages/adapter-bun/index.js @@ -142,7 +142,7 @@ export default function (opts = {}) { const virtual_files = { [manifest_file]: - `export const app_dir = ${JSON.stringify(builder.getAppPath())};\n` + + `export const app_dir = ${JSON.stringify(builder.config.appDir)};\n` + `export const base = ${JSON.stringify(builder.config.paths.base || '/')};\n` + `export const embed = ${JSON.stringify(!!buildOptions.compile)};\n` + `export const env_prefix = ${JSON.stringify(envPrefix)};\n` + diff --git a/packages/adapter-bun/test/adapter.spec.ts b/packages/adapter-bun/test/adapter.spec.ts index 34c514151ac5..0115ede3916a 100644 --- a/packages/adapter-bun/test/adapter.spec.ts +++ b/packages/adapter-bun/test/adapter.spec.ts @@ -121,7 +121,7 @@ describe('Bun build configuration', () => { const files = bun_build.mock.calls[0][0].files; expect(files[manifest_file]).toBe( - 'export const app_dir = "/docs/_app";\n' + + 'export const app_dir = "_app";\n' + 'export const base = "/docs";\n' + 'export const embed = false;\n' + 'export const env_prefix = "APP_";\n' + @@ -578,7 +578,7 @@ function create_builder({ instrumentation?: boolean; } = {}) { return { - config: { outDir: '.svelte-kit', paths: { base, origin } }, + config: { outDir: '.svelte-kit', paths: { base, origin }, appDir: '_app' }, routes, prerendered: { pages: new Map(prerendered_pages), From a2701dcae5803d8241ccd0e30310e4089d6b9912 Mon Sep 17 00:00:00 2001 From: Ottomated Date: Mon, 24 Aug 2026 10:47:16 -0700 Subject: [PATCH 12/18] add service worker to manifest --- packages/kit/src/core/adapt/builder.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index 12a290f5b3ff..fe6193ab66c6 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -106,6 +106,9 @@ export function create_builder({ return facade; }); + if (build_data.service_worker) { + app_manifest.assets.push({ path: build_data.service_worker }); + } return { log, From 5a0f9c7c94827ca0ac3f1e590d63980a31b983bb Mon Sep 17 00:00:00 2001 From: Ottomated Date: Mon, 24 Aug 2026 11:02:16 -0700 Subject: [PATCH 13/18] fix broken tests --- packages/kit/src/core/adapt/builder.spec.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/kit/src/core/adapt/builder.spec.js b/packages/kit/src/core/adapt/builder.spec.js index af76faba6d45..226e6436db42 100644 --- a/packages/kit/src/core/adapt/builder.spec.js +++ b/packages/kit/src/core/adapt/builder.spec.js @@ -54,8 +54,9 @@ test('copy files', () => { }); test('compress files', async () => { - // @ts-expect-error - we don't need the whole config for this test const builder = create_builder({ + // @ts-expect-error - we don't need the whole config for this test + build_data: {}, route_data: [] }); @@ -77,8 +78,9 @@ test('compress files', async () => { }); test('compress returns an empty array for a directory that does not exist', async () => { - // @ts-expect-error - we don't need the whole config for this test const builder = create_builder({ + // @ts-expect-error - we don't need the whole config for this test + build_data: {}, route_data: [] }); @@ -100,8 +102,11 @@ test('instrument generates facade with posix paths', () => { const entrypoint = join(dest, 'index.js'); const instrumentation = join(dest, 'server', 'instrumentation.server.js'); - // @ts-expect-error - we don't need the whole config for this test - const builder = create_builder({ route_data: [] }); + const builder = create_builder({ + // @ts-expect-error - we don't need the whole config for this test + build_data: {}, + route_data: [] + }); builder.instrument({ entrypoint, From 1e44cdaa00fa5119726813434a4538d4309086ef Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 26 Aug 2026 11:07:03 -0700 Subject: [PATCH 14/18] suggestions --- .changeset/smooth-flies-begin.md | 2 +- .../99-writing-adapters.md | 2 +- .../35-migrating-to-sveltekit-3.md | 1 + packages/adapter-bun/index.js | 2 +- packages/adapter-cloudflare/index.js | 2 +- packages/adapter-netlify/files/shims.js | 32 +++++++++++++++++++ packages/adapter-netlify/index.js | 4 +-- packages/adapter-node/index.js | 2 +- packages/adapter-vercel/index.js | 2 +- packages/kit/src/core/adapt/builder.js | 4 +-- packages/kit/src/exports/public.d.ts | 17 +++++++--- packages/kit/types/index.d.ts | 17 +++++++--- 12 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 packages/adapter-netlify/files/shims.js diff --git a/.changeset/smooth-flies-begin.md b/.changeset/smooth-flies-begin.md index da2f9b58f3e1..2b7e723f7228 100644 --- a/.changeset/smooth-flies-begin.md +++ b/.changeset/smooth-flies-begin.md @@ -6,5 +6,5 @@ "@sveltejs/kit": major --- -breaking: replace the `generateManifest` adapter api with `writeServerEntrypoint` and `builder.manifest` +breaking: replace the `generateManifest` adapter api with `generateServerInstance` and `builder.manifest` \ No newline at end of file diff --git a/documentation/docs/25-build-and-deploy/99-writing-adapters.md b/documentation/docs/25-build-and-deploy/99-writing-adapters.md index c788a6571125..77be9c8aeeb4 100644 --- a/documentation/docs/25-build-and-deploy/99-writing-adapters.md +++ b/documentation/docs/25-build-and-deploy/99-writing-adapters.md @@ -60,7 +60,7 @@ Within the `adapt` method, there are a number of things that an adapter should d - Clear out the build directory - Write SvelteKit output with `builder.writeClient`, `builder.writeServer`, and `builder.writePrerendered` - Output code that: - - Imports a `server` instance generated by `${builder.writeServerEntrypoint()}` + - Imports a `server` instance generated by `${builder.generateServerInstance()}` - Runs `await server.init({ env, read })` - Listens for requests from the platform, converts them to a standard [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `server.respond(request, { getClientAddress })` function to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it - expose any platform-specific information to SvelteKit via the `platform` option passed to `server.respond` diff --git a/documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md b/documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md index 71426de4b435..d99fb5dbb27d 100644 --- a/documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md +++ b/documentation/docs/60-appendix/35-migrating-to-sveltekit-3.md @@ -481,6 +481,7 @@ For adapter authors, there are some additional changes: - `builder.createEntries` has been removed — use `builder.writeClient`, `builder.writeServer` and `builder.writePrerendered` directly - `builder.compress` returns a list of compressed files - `builder.mkdirp` and `builder.rimraf` are deprecated in favour of `node:fs` methods +- `builder.generateManifest` has been removed — use `builder.generateServerInstance` to replace it, and `builder.manifest` to access the manifest ## Responses diff --git a/packages/adapter-bun/index.js b/packages/adapter-bun/index.js index 0cc2ede1059f..ae34a56c7230 100644 --- a/packages/adapter-bun/index.js +++ b/packages/adapter-bun/index.js @@ -138,7 +138,7 @@ export default function (opts = {}) { const tmp = builder.getBuildDirectory('bun-tmp'); fs.mkdirSync(tmp, { recursive: true }); - builder.writeServerEntrypoint(`${tmp}/server.js`); + builder.generateServerInstance(`${tmp}/server.js`); const virtual_files = { [manifest_file]: diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index cc81b4c6b32e..74e90850e1fe 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -103,7 +103,7 @@ export default function (options = {}) { // worker const worker_dest_dir = path.dirname(worker_dest); - builder.writeServerEntrypoint(`${tmp}/server.js`); + builder.generateServerInstance(`${tmp}/server.js`); builder.copy(`${files}/worker.js`, worker_dest, { replace: { // the paths returned by the Wrangler config might be Windows paths, diff --git a/packages/adapter-netlify/files/shims.js b/packages/adapter-netlify/files/shims.js new file mode 100644 index 000000000000..9cddad88d532 --- /dev/null +++ b/packages/adapter-netlify/files/shims.js @@ -0,0 +1,32 @@ +import buffer from 'node:buffer'; +import { webcrypto } from 'node:crypto'; + +// `buffer.File` was added in Node 18.13.0 while the `File` global was added in Node 20.0.0 +const File = /** @type {import('node:buffer') & { File?: File}} */ (buffer).File; + +/** @type {Record} */ +const globals = { + crypto: webcrypto, + File +}; + +// exported for dev/preview and node environments +/** + * Make various web APIs available as globals: + * - `crypto` + * - `File` + */ +function installPolyfills() { + for (const name in globals) { + if (name in globalThis) continue; + + Object.defineProperty(globalThis, name, { + enumerable: true, + configurable: true, + writable: true, + value: globals[name] + }); + } +} + +installPolyfills(); diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 2c52b27be6e2..a0708832a35c 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -264,7 +264,7 @@ function write_frameworks_config({ builder }) { * }} opts */ function generate_serverless_function({ builder, routes, patterns, name, type, exclude }) { - builder.writeServerEntrypoint(`.netlify/v1/server-${name}.js`, { + builder.generateServerInstance(`.netlify/v1/server-${name}.js`, { routes, serverDirectory: '.netlify/v1/server' }); @@ -432,7 +432,7 @@ async function generate_edge_functions({ builder }) { } }); - builder.writeServerEntrypoint(`${tmp}/server.js`); + builder.generateServerInstance(`${tmp}/server.js`); const path = '/*'; // We only need to specify paths without the trailing slash because diff --git a/packages/adapter-node/index.js b/packages/adapter-node/index.js index bf8c7db95494..f1e4725e5640 100644 --- a/packages/adapter-node/index.js +++ b/packages/adapter-node/index.js @@ -76,7 +76,7 @@ export default function (opts = {}) { input['instrumentation.server'] = `${server}/instrumentation.server.js`; } - builder.writeServerEntrypoint(`${server}/server.js`); + builder.generateServerInstance(`${server}/server.js`); /** @type {Record} */ const defines = { diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 137247c51352..daa085d3384c 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -72,7 +72,7 @@ const plugin = function (defaults = {}) { instrumentation: `${builder.getServerDirectory()}/instrumentation.server.js` }); } - builder.writeServerEntrypoint(`${tmp}/server.js`, { routes }); + builder.generateServerInstance(`${tmp}/server.js`, { routes }); await create_function_bundle(builder, entrypoint, dir, config); diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index fe6193ab66c6..c961e9271ef1 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -217,11 +217,11 @@ export function create_builder({ generateManifest() { throw new Error( - `The \`generateManifest\` adapter API is deprecated — it has been replaced with \`writeServerEntrypoint\` and \`builder.manifest\`. You may need to update your adapter` + 'The `generateManifest` adapter API has been removed — use `generateServerInstance` or `builder.manifest` instead. You may need to update your adapter' ); }, - writeServerEntrypoint(dest, { routes: subset, serverDirectory } = {}) { + generateServerInstance(dest, { routes: subset, serverDirectory } = {}) { const relative = relative_path( path.dirname(dest), serverDirectory ?? this.getServerDirectory() diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 6fff2dd40cb0..0007aadc14b8 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -139,9 +139,15 @@ export interface Builder { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; - /** The value of the `$app/manifest` module */ + /** + * The value of the `$app/manifest` module + * @since 3.0.0 + */ manifest: typeof import('$app/manifest'); - /** A record of file extensions to MIME types */ + /** + * A record of file extensions to MIME types + * @since 3.0.0 + */ mimeTypes: Record; /** @@ -170,7 +176,7 @@ export interface Builder { * Generate a server-side manifest to initialise the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) with. * @param opts * @param opts.relativePath A relative path to the base directory of the server build output - * @deprecated removed in 3.0. Use `builder.writeServerEntrypoint` or `builder.manifest` instead + * @deprecated removed in 3.0. Use `builder.generateServerInstance` or `builder.manifest` instead */ generateManifest?: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; @@ -187,12 +193,13 @@ export interface Builder { getAppPath: () => string; /** - * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). + * Generates a module exposing a SvelteKit [Server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) instance. * @param dest * @param opts.routes A subset of the routes to include in the server's manifest * @param opts.serverDirectory The directory containing the server code. Defaults to `getServerDirectory()`. + * @since 3.0.0 */ - writeServerEntrypoint: ( + generateServerInstance: ( dest: string, opts?: { routes?: RouteDefinition[]; diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 2f81cb25970b..310ce276e48f 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -125,9 +125,15 @@ declare module '@sveltejs/kit' { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; - /** The value of the `$app/manifest` module */ + /** + * The value of the `$app/manifest` module + * @since 3.0.0 + */ manifest: typeof import('$app/manifest'); - /** A record of file extensions to MIME types */ + /** + * A record of file extensions to MIME types + * @since 3.0.0 + */ mimeTypes: Record; /** @@ -155,7 +161,7 @@ declare module '@sveltejs/kit' { /** * Generate a server-side manifest to initialise the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) with. * @param opts.relativePath A relative path to the base directory of the server build output - * @deprecated removed in 3.0. Use `builder.writeServerEntrypoint` or `builder.manifest` instead + * @deprecated removed in 3.0. Use `builder.generateServerInstance` or `builder.manifest` instead */ generateManifest?: (opts: { relativePath: string; routes?: RouteDefinition[] }) => string; @@ -172,11 +178,12 @@ declare module '@sveltejs/kit' { getAppPath: () => string; /** - * Writes a javascript file that initialises the SvelteKit [server](https://svelte.dev/docs/kit/@sveltejs-kit#Server). + * Generates a module exposing a SvelteKit [Server](https://svelte.dev/docs/kit/@sveltejs-kit#Server) instance. * @param opts.routes A subset of the routes to include in the server's manifest * @param opts.serverDirectory The directory containing the server code. Defaults to `getServerDirectory()`. + * @since 3.0.0 */ - writeServerEntrypoint: ( + generateServerInstance: ( dest: string, opts?: { routes?: RouteDefinition[]; From 42ff77dca98b18dcb9f2f17a55f637e7f0b8610e Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 26 Aug 2026 11:15:05 -0700 Subject: [PATCH 15/18] fix bun test --- packages/adapter-bun/test/adapter.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/adapter-bun/test/adapter.spec.ts b/packages/adapter-bun/test/adapter.spec.ts index 0115ede3916a..f5fa75f984c5 100644 --- a/packages/adapter-bun/test/adapter.spec.ts +++ b/packages/adapter-bun/test/adapter.spec.ts @@ -130,7 +130,7 @@ describe('Bun build configuration', () => { expect(files[options_file]).toBe( 'export default {"hostname":"127.0.0.1","port":4000,"development":true};' ); - expect(builder.writeServerEntrypoint).toHaveBeenCalledWith( + expect(builder.generateServerInstance).toHaveBeenCalledWith( '.svelte-kit/output/bun-tmp/server.js' ); }); @@ -591,7 +591,7 @@ function create_builder({ info: mock((_message: string) => {}) }, getAppPath: () => `${base}/_app`, - writeServerEntrypoint: mock(() => {}), + generateServerInstance: mock(() => {}), getBuildDirectory: (dir: string) => `.svelte-kit/output/${dir}`, getServerDirectory: () => '.svelte-kit/output/server', writeClient: mock(() => client_files), From 5ec53b0043d15cb9d904b52a79bb9f7927d9e34b Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 26 Aug 2026 12:52:17 -0700 Subject: [PATCH 16/18] comments about $app/manifest difference --- packages/kit/src/core/adapt/builder.js | 4 ++++ packages/kit/src/exports/public.d.ts | 7 ++++--- packages/kit/types/index.d.ts | 7 ++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/kit/src/core/adapt/builder.js b/packages/kit/src/core/adapt/builder.js index c961e9271ef1..2a0790567988 100644 --- a/packages/kit/src/core/adapt/builder.js +++ b/packages/kit/src/core/adapt/builder.js @@ -106,6 +106,9 @@ export function create_builder({ return facade; }); + + // $app/manifest cannot include the service worker because it's used by the service worker itself, + // but the adapter needs to know about it so we add it here. if (build_data.service_worker) { app_manifest.assets.push({ path: build_data.service_worker }); } @@ -121,6 +124,7 @@ export function create_builder({ routes, manifest: app_manifest, get mimeTypes() { + // TODO - make the `generate_manifest` function return data instead of a string, and retrieve mime types from there const mime_types = get_mime_lookup(build_data.manifest_data); const server_assets = find_server_assets( build_data, diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 0007aadc14b8..83070be7a60f 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -139,12 +139,13 @@ export interface Builder { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; - /** - * The value of the `$app/manifest` module + /** + * The value of the `$app/manifest` module. + * The only difference is `manifest.assets` also includes the service worker, if it exists. * @since 3.0.0 */ manifest: typeof import('$app/manifest'); - /** + /** * A record of file extensions to MIME types * @since 3.0.0 */ diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 310ce276e48f..f060bdc20629 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -125,12 +125,13 @@ declare module '@sveltejs/kit' { prerendered: Prerendered; /** An array of all routes (including prerendered) */ routes: RouteDefinition[]; - /** - * The value of the `$app/manifest` module + /** + * The value of the `$app/manifest` module. + * The only difference is `manifest.assets` also includes the service worker, if it exists. * @since 3.0.0 */ manifest: typeof import('$app/manifest'); - /** + /** * A record of file extensions to MIME types * @since 3.0.0 */ From 12cbb5daca3e3bea3959e921e5606a1966b4f5bf Mon Sep 17 00:00:00 2001 From: Ottomated Date: Wed, 26 Aug 2026 13:33:08 -0700 Subject: [PATCH 17/18] how did you sneak in here --- packages/adapter-netlify/files/shims.js | 32 ------------------------- 1 file changed, 32 deletions(-) delete mode 100644 packages/adapter-netlify/files/shims.js diff --git a/packages/adapter-netlify/files/shims.js b/packages/adapter-netlify/files/shims.js deleted file mode 100644 index 9cddad88d532..000000000000 --- a/packages/adapter-netlify/files/shims.js +++ /dev/null @@ -1,32 +0,0 @@ -import buffer from 'node:buffer'; -import { webcrypto } from 'node:crypto'; - -// `buffer.File` was added in Node 18.13.0 while the `File` global was added in Node 20.0.0 -const File = /** @type {import('node:buffer') & { File?: File}} */ (buffer).File; - -/** @type {Record} */ -const globals = { - crypto: webcrypto, - File -}; - -// exported for dev/preview and node environments -/** - * Make various web APIs available as globals: - * - `crypto` - * - `File` - */ -function installPolyfills() { - for (const name in globals) { - if (name in globalThis) continue; - - Object.defineProperty(globalThis, name, { - enumerable: true, - configurable: true, - writable: true, - value: globals[name] - }); - } -} - -installPolyfills(); From 8d7123e1bea2e527d8e6841be165ad0f76defb50 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Thu, 27 Aug 2026 04:38:42 +0800 Subject: [PATCH 18/18] Apply suggestion from @teemingc --- .changeset/smooth-flies-begin.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/smooth-flies-begin.md b/.changeset/smooth-flies-begin.md index 2b7e723f7228..80d6c5efc17a 100644 --- a/.changeset/smooth-flies-begin.md +++ b/.changeset/smooth-flies-begin.md @@ -6,5 +6,5 @@ "@sveltejs/kit": major --- -breaking: replace the `generateManifest` adapter api with `generateServerInstance` and `builder.manifest` +breaking: replace the `builder.generateManifest` with `builder.generateServerInstance` and `builder.manifest` \ No newline at end of file