From 2f3609d4cafa644ca45108fb1f0f275384723df8 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:57:49 +0800 Subject: [PATCH 01/12] remove support for cloudflare pages --- .../60-adapter-cloudflare.md | 92 +++-------- packages/adapter-cloudflare/index.d.ts | 35 +--- packages/adapter-cloudflare/index.js | 121 ++++---------- packages/adapter-cloudflare/utils.js | 98 ++--------- packages/adapter-cloudflare/utils.spec.js | 153 ------------------ 5 files changed, 67 insertions(+), 432 deletions(-) diff --git a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md index 82c07a1df3aa..083954adfd8c 100644 --- a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md +++ b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md @@ -2,13 +2,11 @@ title: Cloudflare --- -To deploy to [Cloudflare Workers](https://workers.cloudflare.com/) or [Cloudflare Pages](https://pages.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare). - -This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `event.platform` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided. +To deploy to [Cloudflare Workers](https://workers.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare). ## Comparisons -- `adapter-cloudflare` – supports all SvelteKit features; builds for Cloudflare Workers Static Assets and Cloudflare Pages +- `adapter-cloudflare` – supports all SvelteKit features; builds for Cloudflare Workers Static Assets - `adapter-cloudflare-workers` – deprecated. Supports all SvelteKit features; builds for Cloudflare Workers Sites - `adapter-static` – only produces client-side static assets; compatible with Cloudflare Workers Static Assets and Cloudflare Pages @@ -34,11 +32,7 @@ export default defineConfig({ environment: undefined, persist: undefined }, - fallback: 'plaintext', - routes: { - include: ['/*'], - exclude: [''] - } + fallback: 'plaintext' }) }) ] @@ -59,31 +53,9 @@ Preferences for the emulated `platform.env` local bindings. See the [getPlatform Whether to render a plaintext 404.html page or a rendered SPA fallback page for non-matching asset requests. -For Cloudflare Workers, the default behaviour is to return a null-body 404-status response for non-matching assets requests. However, if the [`assets.not_found_handling`](https://developers.cloudflare.com/workers/static-assets/routing/#2-not_found_handling) Wrangler configuration setting is set to `"404-page"`, this page will be served if a request fails to match an asset. If `assets.not_found_handling` is set to `"single-page-application"`, the adapter will render a SPA fallback `index.html` page regardless of the `fallback` option specified. - -For Cloudflare Pages, this page will only be served when a request that matches an entry in `routes.exclude` fails to match an asset. - -Most of the time `plaintext` is sufficient, but if you are using `routes.exclude` to manually exclude a set of prerendered pages without exceeding the 100 route limit, you may wish to use `spa` instead to avoid showing an unstyled 404 page to users. - -See Cloudflare Pages' [Not Found behaviour](https://developers.cloudflare.com/pages/configuration/serving-pages/#not-found-behavior) for more info. - -### routes - -Only for Cloudflare Pages. Allows you to customise the [`_routes.json`](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file) file generated by `adapter-cloudflare`. - -- `include` defines routes that will invoke a function, and defaults to `['/*']` -- `exclude` defines routes that will _not_ invoke a function — this is a faster and cheaper way to serve your app's static assets. This array can include the following special values: - - `` contains your app's build artifacts (the files generated by Vite) - - `` contains the contents of your `static` directory - - `` contains a list of pathnames from your [`_redirects` file](https://developers.cloudflare.com/pages/configuration/redirects/) at the root - - `` contains a list of prerendered pages - - `` (the default) contains all of the above - -You can have up to 100 `include` and `exclude` rules combined. Generally you can omit the `routes` options, but if (for example) your `` paths exceed that limit, you may find it helpful to manually create an `exclude` list that includes `'/articles/*'` instead of the auto-generated `['/articles/foo', '/articles/bar', '/articles/baz', ...]`. +The default behaviour is to return a null-body 404-status response for non-matching assets requests. However, if the [`assets.not_found_handling`](https://developers.cloudflare.com/workers/static-assets/routing/#2-not_found_handling) Wrangler configuration setting is set to `"404-page"`, this page will be served if a request fails to match an asset. If `assets.not_found_handling` is set to `"single-page-application"`, the adapter will render a SPA fallback `index.html` page regardless of the `fallback` option specified. -## Cloudflare Workers - -### Basic configuration +## Basic configuration When building for Cloudflare Workers, this adapter expects to find a [Wrangler configuration file](https://developers.cloudflare.com/workers/configuration/sites/configuration/) in the project root. It should look something like this: @@ -101,32 +73,9 @@ When building for Cloudflare Workers, this adapter expects to find a [Wrangler c } ``` -### Deployment - -You can use the Wrangler CLI to deploy your application by running `npx wrangler deploy` or use the [Cloudflare Git integration](https://developers.cloudflare.com/workers/ci-cd/builds/) to enable automatic builds and deployments on push. - -## Cloudflare Pages - -### Deployment - -Please follow the [Get Started Guide](https://developers.cloudflare.com/pages/get-started/) for Cloudflare Pages to begin. - -If you're using the [Git integration](https://developers.cloudflare.com/pages/get-started/git-integration/), your build settings should look like this: - -- Framework preset – SvelteKit -- Build command – `npm run build` or `vite build` -- Build output directory – `.svelte-kit/cloudflare` +## Deployment - -Once configured, go to the **Runtime** section of your project settings, and add the `nodejs_als` compatibility flag to enable the [Node.js AsyncLocalStorage](https://developers.cloudflare.com/workers/configuration/compatibility-flags/#nodejs-asynclocalstorage). Alternatively, do this in your wrangler config using the `compatibility_flags` array. - -### Further reading - -You may wish to refer to [Cloudflare's documentation for deploying a SvelteKit site on Cloudflare Pages](https://developers.cloudflare.com/pages/framework-guides/deploy-a-svelte-kit-site/). - -### Notes - -Functions contained in the [`/functions` directory](https://developers.cloudflare.com/pages/functions/routing/) at the project's root will _not_ be included in the deployment. Instead, functions should be implemented as [server endpoints](routing#server) in your SvelteKit app, which is compiled to a [single `_worker.js` file](https://developers.cloudflare.com/pages/functions/advanced-mode/). +You can use [Wrangler](https://developers.cloudflare.com/workers/wrangler/) to deploy your application by running `npx wrangler deploy` or use the [Cloudflare Git integration](https://developers.cloudflare.com/workers/ci-cd/builds/) to enable automatic builds and deployments on push. ## Runtime APIs @@ -157,19 +106,26 @@ export async function POST({ request, platform }) { > [!NOTE] SvelteKit's built-in [`$app/env/*` modules](environment-variables) should be preferred for environment variables. -To make these types available to your app, install [`@cloudflare/workers-types`](https://www.npmjs.com/package/@cloudflare/workers-types) and reference them in your `src/app.d.ts`: +After configuring the bindings in your Wrangler configuration file, you can add type-safety by running [`npx wrangler types`](https://developers.cloudflare.com/workers/languages/typescript/) and adding the generated types to your `tsconfig.json`. + +```json +/// file: tsconfig.json +{ + "compilerOptions": { + +++"types": ["worker-configuration.d.ts"]+++ + } +} +``` + +Finally, add `Env` to the `platform.env` property in `src/app.d.ts`: ```ts +// @errors: 2304 /// file: src/app.d.ts -+++import { KVNamespace, DurableObjectNamespace } from '@cloudflare/workers-types';+++ - declare global { namespace App { interface Platform { -+++ env: { - YOUR_KV_NAMESPACE: KVNamespace; - YOUR_DURABLE_OBJECT_NAMESPACE: DurableObjectNamespace; - };+++ ++++ env: Env;+++ } } } @@ -181,7 +137,7 @@ export {}; Cloudflare specific values in the `platform` property are emulated during dev and preview modes. Local [bindings](https://developers.cloudflare.com/workers/wrangler/configuration/#bindings) are created based on your [Wrangler configuration file](https://developers.cloudflare.com/workers/wrangler/) and are used to populate `platform.env` during development and preview. Use the adapter config [`platformProxy` option](#Options-platformProxy) to change your preferences for the bindings. -For testing the build, you should use [Wrangler](https://developers.cloudflare.com/workers/wrangler/) version 4. Once you have built your site, run `wrangler dev .svelte-kit/cloudflare/_worker.js` if you're testing for Cloudflare Workers or `wrangler pages dev .svelte-kit/cloudflare` for Cloudflare Pages. +For testing the build, you should use [Wrangler](https://developers.cloudflare.com/workers/wrangler/) version 4. Once you have built your site, run `wrangler dev .svelte-kit/cloudflare/_worker.js`. ## Headers and redirects @@ -214,6 +170,10 @@ Instead, use the [`read`]($app-server#read) function from `$app/server` to acces Alternatively, you can [prerender](page-options#prerender) the routes in question. +## Migrating from Pages + +Cloudflare Workers is now preferred over Pages because of its broader feature set. You should follow the [official migration guide](https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/) to redeploy your project to Workers before deleting your Pages project. + ## Migrating from Workers Sites Cloudflare no longer recommends using [Workers Sites](https://developers.cloudflare.com/workers/configuration/sites/configuration/) and instead recommends using [Workers Static Assets](https://developers.cloudflare.com/workers/static-assets/). To migrate, replace `@sveltejs/adapter-cloudflare-workers` with `@sveltejs/adapter-cloudflare` and remove all `site` configuration settings from your Wrangler configuration file, then add the `assets.directory` and `assets.binding` configuration settings: diff --git a/packages/adapter-cloudflare/index.d.ts b/packages/adapter-cloudflare/index.d.ts index b9062094bd08..d3714269ff64 100644 --- a/packages/adapter-cloudflare/index.d.ts +++ b/packages/adapter-cloudflare/index.d.ts @@ -36,29 +36,9 @@ export interface AdapterOptions { /** * Only for Cloudflare Pages. Customize the automatically-generated [`_routes.json`](https://developers.cloudflare.com/pages/platform/functions/routing/#create-a-_routesjson-file) file. + * @deprecated */ - routes?: { - /** - * Routes that will be invoked by functions. Accepts wildcards. - * @default ["/*"] - */ - include?: string[]; - - /** - * Routes that will not be invoked by functions. Accepts wildcards. - * `exclude` takes priority over `include`. - * - * To have the adapter automatically exclude certain things, you can use these placeholders: - * - * - `` to exclude build artifacts (files generated by Vite) - * - `` for the contents of your `static` directory - * - `` for prerendered routes - * - `` to exclude all of the above - * - * @default [""] - */ - exclude?: string[]; - }; + routes?: never; /** * Config object passed to [`getPlatformProxy`](https://developers.cloudflare.com/workers/wrangler/api/#getplatformproxy) @@ -66,14 +46,3 @@ export interface AdapterOptions { */ platformProxy?: GetPlatformProxyOptions; } - -/** - * The JSON format of the {@link https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file | `_routes.json`} - * file that controls when the Cloudflare Pages Function is invoked. - */ -export interface RoutesJSONSpec { - version: 1; - description: string; - include: string[]; - exclude: string[]; -} diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index c39f57e61521..6d4a8f370a40 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -6,8 +6,6 @@ import { getPlatformProxy, unstable_readConfig } from 'wrangler'; import { is_building_for_cloudflare_pages, validate_worker_settings, - get_routes_json, - parse_redirects, append_headers } from './utils.js'; @@ -18,15 +16,6 @@ export default function (options = {}) { return { name, async adapt(builder) { - if ( - existsSync('_routes.json') || - existsSync(`${builder.config.kit.files.assets}/_routes.json`) - ) { - throw new Error( - "Cloudflare Pages' _routes.json should be configured from the adapter option of the SvelteKit plugin in your vite.config.js. See https://svelte.dev/docs/kit/adapter-cloudflare#Options-routes" - ); - } - if (existsSync(`${builder.config.kit.files.assets}/_headers`)) { throw new Error( `The _headers file should be placed in the project root rather than the ${builder.config.kit.files.assets} directory` @@ -39,34 +28,34 @@ export default function (options = {}) { ); } - const { wrangler_config, building_for_cloudflare_pages } = validate_wrangler_config( - options.config - ); + const wrangler_config = unstable_readConfig({ config: options.config }); + + // TODO: remove migration helper in a future major version + if (is_building_for_cloudflare_pages(wrangler_config)) { + throw new Error( + '@sveltejs/adapter-cloudflare no longer supports Cloudflare Pages. Please follow the migration guide to move your project to Cloudflare Workers https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/' + ); + } + + validate_worker_settings(wrangler_config); let dest = builder.getBuildDirectory('cloudflare'); let worker_dest = `${dest}/_worker.js`; let assets_binding = 'ASSETS'; - if (building_for_cloudflare_pages) { - if (wrangler_config.pages_build_output_dir) { - dest = wrangler_config.pages_build_output_dir; - worker_dest = `${dest}/_worker.js`; - } - } else { - if (wrangler_config.main) { - worker_dest = wrangler_config.main; - } - if (wrangler_config.assets?.directory) { - // wrangler doesn't resolve `assets.directory` to an absolute path unlike - // `main` and `pages_build_output_dir` so we need to do it ourselves here - const parent_dir = wrangler_config.configPath - ? path.dirname(path.resolve(wrangler_config.configPath)) - : process.cwd(); - dest = path.resolve(parent_dir, wrangler_config.assets.directory); - } - if (wrangler_config.assets?.binding) { - assets_binding = wrangler_config.assets.binding; - } + if (wrangler_config.main) { + worker_dest = wrangler_config.main; + } + if (wrangler_config.assets?.directory) { + // wrangler doesn't resolve `assets.directory` to an absolute path unlike + // `main` and `pages_build_output_dir` so we need to do it ourselves here + const parent_dir = wrangler_config.configPath + ? path.dirname(path.resolve(wrangler_config.configPath)) + : process.cwd(); + dest = path.resolve(parent_dir, wrangler_config.assets.directory); + } + if (wrangler_config.assets?.binding) { + assets_binding = wrangler_config.assets.binding; } const files = fileURLToPath(new URL('./files', import.meta.url).href); @@ -81,10 +70,7 @@ export default function (options = {}) { // client assets and prerendered pages const assets_dest = `${dest}${builder.config.kit.paths.base}`; builder.mkdirp(assets_dest); - if ( - building_for_cloudflare_pages || - wrangler_config.assets?.not_found_handling === '404-page' - ) { + if (wrangler_config.assets?.not_found_handling === '404-page') { // generate plaintext 404.html first which can then be overridden by prerendering, if the user defined such a page. // This file is served when a request fails to match an asset. // If we're building for Cloudflare Pages, it's only served when a request matches an entry in `routes.exclude` @@ -95,12 +81,9 @@ export default function (options = {}) { writeFileSync(fallback, 'Not Found'); } } - const client_assets = builder.writeClient(assets_dest); + builder.writeClient(assets_dest); builder.writePrerendered(assets_dest); - if ( - !building_for_cloudflare_pages && - wrangler_config.assets?.not_found_handling === 'single-page-application' - ) { + if (wrangler_config.assets?.not_found_handling === 'single-page-application') { await builder.generateFallback(path.join(assets_dest, 'index.html')); } @@ -153,38 +136,17 @@ export default function (options = {}) { }); } - if (building_for_cloudflare_pages) { - // _routes.json - - // we need to add the source paths found in the `_redirects` file to the - // `_routes.json` file so that Cloudflare knows it shouldn't invoke the - // Worker but instead let the rules in the `_redirects` file take over. - /** @type {string[]} */ - let redirects = []; - if (existsSync(redirects_dest)) { - const redirect_rules = readFileSync(redirects_dest, 'utf8'); - redirects = parse_redirects(redirect_rules); - } - - writeFileSync( - `${dest}/_routes.json`, - JSON.stringify( - get_routes_json(builder, client_assets, redirects, options.routes ?? {}), - null, - '\t' - ) - ); - } else { - writeFileSync(`${dest}/.assetsignore`, generate_assetsignore(), { flag: 'a' }); - } + writeFileSync(`${dest}/.assetsignore`, generate_assetsignore(), { flag: 'a' }); }, emulate() { // we want to invoke `getPlatformProxy` only once, but await it only when it is accessed. // If we would await it here, it would hang indefinitely because the platform proxy only resolves once a request happens const get_emulated = async () => { const proxy = await getPlatformProxy(options.platformProxy); + /** @type {App.Platform} */ const platform = { env: proxy.env, + // @ts-expect-error cloudflare type discrepencies ctx: proxy.ctx, context: proxy.ctx, // deprecated in favor of ctx caches: proxy.caches, @@ -203,6 +165,7 @@ export default function (options = {}) { return { platform, prerender_platform }; }; + /** @type {Awaited>} */ let emulated; return { @@ -270,30 +233,6 @@ _redirects `.trimEnd(); } -/** - * @param {string | undefined} config_file - * @returns {{ - * wrangler_config: import('wrangler').Unstable_Config, - * building_for_cloudflare_pages: boolean - * }} - */ -function validate_wrangler_config(config_file = undefined) { - const wrangler_config = unstable_readConfig({ config: config_file }); - - const building_for_cloudflare_pages = is_building_for_cloudflare_pages(wrangler_config); - - // we don't need to validate the config if we're building for Cloudflare Pages - // because the `main` and `assets` values cannot be changed there - if (!building_for_cloudflare_pages) { - validate_worker_settings(wrangler_config); - } - - return { - wrangler_config, - building_for_cloudflare_pages - }; -} - /** @param {string} str */ function posixify(str) { return str.replace(/\\/g, '/'); diff --git a/packages/adapter-cloudflare/utils.js b/packages/adapter-cloudflare/utils.js index 90e45a27a3b9..de12faa11099 100644 --- a/packages/adapter-cloudflare/utils.js +++ b/packages/adapter-cloudflare/utils.js @@ -1,11 +1,17 @@ +/** @import { Unstable_Config } from 'wrangler' */ +import { existsSync } from 'node:fs'; import process from 'node:process'; /** - * @param {import('wrangler').Unstable_Config} wrangler_config + * @param {Unstable_Config} wrangler_config * @returns {boolean} */ export function is_building_for_cloudflare_pages(wrangler_config) { - if (process.env.CF_PAGES || wrangler_config.pages_build_output_dir) { + if ( + process.env.CF_PAGES || + wrangler_config.pages_build_output_dir || + existsSync('_routes.json') + ) { return true; } @@ -17,7 +23,7 @@ export function is_building_for_cloudflare_pages(wrangler_config) { } /** - * @param {import('wrangler').Unstable_Config} wrangler_config + * @param {Unstable_Config} wrangler_config */ export function validate_worker_settings(wrangler_config) { const config_path = wrangler_config.configPath || 'your wrangler.jsonc file'; @@ -78,92 +84,6 @@ export function parse_redirects(file_contents) { return redirects; } -/** - * Generates the [_routes.json](https://developers.cloudflare.com/pages/functions/routing/#create-a-_routesjson-file) - * file that dictates which routes invoke the Cloudflare Worker. - * @param {import('@sveltejs/kit').Builder} builder - * @param {string[]} client_assets - * @param {string[]} redirects - * @param {import('./index.js').AdapterOptions['routes']} routes - * @returns {import('./index.js').RoutesJSONSpec} - */ -export function get_routes_json(builder, client_assets, redirects, routes) { - const include = routes?.include ?? ['/*']; - let exclude = routes?.exclude ?? ['']; - - if (!Array.isArray(include) || !Array.isArray(exclude)) { - throw new Error('routes.include and routes.exclude must be arrays'); - } - - if (include?.length === 0) { - throw new Error('routes.include must contain at least one route'); - } - - if (include?.length > 100) { - throw new Error('routes.include must contain 100 or fewer routes'); - } - - /** @type {Set} */ - const transformed_rules = new Set(); - for (const rule of exclude) { - if (rule === '') { - transformed_rules.add(''); - transformed_rules.add(''); - transformed_rules.add(''); - transformed_rules.add(''); - } else { - transformed_rules.add(rule); - } - } - - /** @type {Set} */ - const excluded_routes = new Set(); - for (const rule of transformed_rules) { - if (rule === '') { - const app_path = builder.getAppPath(); - excluded_routes.add(`/${app_path}/version.json`); - excluded_routes.add(`/${app_path}/immutable/*`); - continue; - } - - if (rule === '') { - for (const file of client_assets) { - if (file.startsWith(`${builder.config.kit.appDir}/`)) continue; - excluded_routes.add(`${builder.config.kit.paths.base}/${file}`); - } - continue; - } - - if (rule === '') { - builder.prerendered.paths.forEach((path) => excluded_routes.add(path)); - continue; - } - - if (rule === '') { - redirects.forEach((path) => excluded_routes.add(path)); - continue; - } - - excluded_routes.add(rule); - } - exclude = Array.from(excluded_routes); - - const excess = include.length + exclude.length - 100; - if (excess > 0) { - builder.log.warn( - `Cloudflare Pages Functions' includes/excludes exceeds _routes.json limits (see https://developers.cloudflare.com/pages/platform/functions/routing/#limits). Dropping ${excess} exclude rules — this will cause unnecessary function invocations.` - ); - exclude.length -= excess; - } - - return { - version: 1, - description: 'Generated by @sveltejs/adapter-cloudflare', - include, - exclude - }; -} - /** * Adds header rules to the contents of a `_headers` file * @param {string} url diff --git a/packages/adapter-cloudflare/utils.spec.js b/packages/adapter-cloudflare/utils.spec.js index 23eab83422fb..58bba1b3bd1a 100644 --- a/packages/adapter-cloudflare/utils.spec.js +++ b/packages/adapter-cloudflare/utils.spec.js @@ -2,7 +2,6 @@ import { describe, test, vi, expect } from 'vitest'; import { is_building_for_cloudflare_pages, validate_worker_settings, - get_routes_json, parse_redirects, append_headers } from './utils.js'; @@ -222,155 +221,3 @@ describe('_redirects', () => { expect(redirects).toEqual(['/home301', '/blog/*']); }); }); - -describe('_routes.json', () => { - test('generates file contents', () => { - const routes = get_routes_json( - { - getAppPath: () => 'base-path/_app', - config: { - kit: { - appDir: '_app', - paths: { - base: '/base-path', - assets: '', - origin: 'http://localhost', - relative: true - }, - alias: {}, - csrf: { - checkOrigin: true, - trustedOrigins: [] - }, - embedded: false, - files: { - src: 'src', - assets: 'static', - hooks: { - client: 'src/hooks.client.js', - server: 'src/hooks.server.js', - universal: 'src/hooks.js' - }, - params: 'src/params', - routes: 'src/routes', - serviceWorker: 'src/service-worker.js', - appTemplate: 'src/app.html', - errorTemplate: 'src/error.html' - }, - inlineStyleThreshold: 0, - moduleExtensions: ['.js', '.ts'], - csp: { - mode: 'auto', - // @ts-ignore - directives: {}, - // @ts-ignore - reportOnly: {} - }, - env: { - dir: '.' - }, - outDir: '.svelte-kit' - } - }, - prerendered: { - paths: ['/base-path/prerendered'], - pages: new Map(), - assets: new Map(), - redirects: new Map() - } - }, - ['_app/immutable/this-should-not-be-excluded.js', 'robots.txt'], - ['/base-path/redirect'], - undefined - ); - - expect(routes).toEqual({ - version: 1, - description: 'Generated by @sveltejs/adapter-cloudflare', - include: ['/*'], - exclude: [ - '/base-path/_app/version.json', - '/base-path/_app/immutable/*', - '/base-path/robots.txt', - '/base-path/prerendered', - '/base-path/redirect' - ] - }); - }); - - test('truncates excess exclude rules', () => { - const routes = get_routes_json( - { - // @ts-ignore - log: { - warn: console.warn - }, - getAppPath: () => 'base-path/_app', - config: { - kit: { - appDir: '_app', - paths: { - base: '/base-path', - assets: '', - origin: 'http://localhost', - relative: true - }, - alias: {}, - csrf: { - checkOrigin: true, - trustedOrigins: [] - }, - embedded: false, - files: { - src: 'src', - assets: 'static', - hooks: { - client: 'src/hooks.client.js', - server: 'src/hooks.server.js', - universal: 'src/hooks.js' - }, - params: 'src/params', - routes: 'src/routes', - serviceWorker: 'src/service-worker.js', - appTemplate: 'src/app.html', - errorTemplate: 'src/error.html' - }, - inlineStyleThreshold: 0, - moduleExtensions: ['.js', '.ts'], - csp: { - mode: 'auto', - // @ts-ignore - directives: {}, - // @ts-ignore - reportOnly: {} - }, - env: { - dir: '.' - }, - outDir: '.svelte-kit' - } - }, - prerendered: { - paths: Array.from({ length: 100 }, (_, i) => `/base-path/blog/post/${i + 1}`), - pages: new Map(), - assets: new Map(), - redirects: new Map() - } - }, - ['_app/immutable/this-should-not-be-excluded.js', 'robots.txt'], - [], - undefined - ); - - expect(routes).toEqual({ - version: 1, - description: 'Generated by @sveltejs/adapter-cloudflare', - include: ['/*'], - exclude: [ - '/base-path/_app/version.json', - '/base-path/_app/immutable/*', - '/base-path/robots.txt' - ].concat(Array.from({ length: 96 }, (_, i) => `/base-path/blog/post/${i + 1}`)) - }); - }); -}); From 4adefb65f76dc2802cfc5f05c4a6070005e31f13 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:59:04 +0800 Subject: [PATCH 02/12] delete pages tests --- .../test/apps/pages/.gitignore | 4 ---- .../test/apps/pages/package.json | 21 ------------------- .../test/apps/pages/playwright.config.js | 1 - .../apps/pages/server-side-dep/index.d.ts | 1 - .../test/apps/pages/server-side-dep/index.js | 4 ---- .../apps/pages/server-side-dep/package.json | 11 ---------- .../test/apps/pages/src/app.html | 11 ---------- .../apps/pages/src/routes/+page.server.js | 8 ------- .../test/apps/pages/src/routes/+page.svelte | 5 ----- .../test/apps/pages/test/test.js | 6 ------ .../test/apps/pages/tsconfig.json | 13 ------------ .../test/apps/pages/vite.config.js | 12 ----------- 12 files changed, 97 deletions(-) delete mode 100644 packages/adapter-cloudflare/test/apps/pages/.gitignore delete mode 100644 packages/adapter-cloudflare/test/apps/pages/package.json delete mode 100644 packages/adapter-cloudflare/test/apps/pages/playwright.config.js delete mode 100644 packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.d.ts delete mode 100644 packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.js delete mode 100644 packages/adapter-cloudflare/test/apps/pages/server-side-dep/package.json delete mode 100644 packages/adapter-cloudflare/test/apps/pages/src/app.html delete mode 100644 packages/adapter-cloudflare/test/apps/pages/src/routes/+page.server.js delete mode 100644 packages/adapter-cloudflare/test/apps/pages/src/routes/+page.svelte delete mode 100644 packages/adapter-cloudflare/test/apps/pages/test/test.js delete mode 100644 packages/adapter-cloudflare/test/apps/pages/tsconfig.json delete mode 100644 packages/adapter-cloudflare/test/apps/pages/vite.config.js diff --git a/packages/adapter-cloudflare/test/apps/pages/.gitignore b/packages/adapter-cloudflare/test/apps/pages/.gitignore deleted file mode 100644 index 1bd7b63de4b6..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -node_modules -/.svelte-kit -/.wrangler \ No newline at end of file diff --git a/packages/adapter-cloudflare/test/apps/pages/package.json b/packages/adapter-cloudflare/test/apps/pages/package.json deleted file mode 100644 index dfd08f7249cc..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "test-cloudflare-pages", - "version": "0.0.1", - "private": true, - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "wrangler pages dev .svelte-kit/cloudflare --port 8787 --compatibility-date 2026-06-24", - "prepare": "svelte-kit sync || echo ''", - "test": "playwright test" - }, - "devDependencies": { - "@sveltejs/kit": "workspace:^", - "@sveltejs/vite-plugin-svelte": "catalog:", - "server-side-dep": "file:server-side-dep", - "svelte": "catalog:", - "vite": "catalog:", - "wrangler": "catalog:" - }, - "type": "module" -} diff --git a/packages/adapter-cloudflare/test/apps/pages/playwright.config.js b/packages/adapter-cloudflare/test/apps/pages/playwright.config.js deleted file mode 100644 index 33d36b651014..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/playwright.config.js +++ /dev/null @@ -1 +0,0 @@ -export { config as default } from '../../utils.js'; diff --git a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.d.ts b/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.d.ts deleted file mode 100644 index 0e1188e04a67..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export function sum(a: number, b: number): number; diff --git a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.js b/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.js deleted file mode 100644 index 568b90577d43..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/index.js +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('./index.js').sum} */ -export function sum(a, b) { - return a + b; -} diff --git a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/package.json b/packages/adapter-cloudflare/test/apps/pages/server-side-dep/package.json deleted file mode 100644 index 5b26c9d1855a..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/server-side-dep/package.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "name": "server-side-dep", - "version": "0.0.1", - "type": "module", - "exports": { - ".": { - "default": "./index.js", - "types": "./index.d.ts" - } - } -} diff --git a/packages/adapter-cloudflare/test/apps/pages/src/app.html b/packages/adapter-cloudflare/test/apps/pages/src/app.html deleted file mode 100644 index d533c5e31716..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/src/app.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - %sveltekit.head% - - -
%sveltekit.body%
- - diff --git a/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.server.js b/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.server.js deleted file mode 100644 index 0eeb7d398ffd..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.server.js +++ /dev/null @@ -1,8 +0,0 @@ -// this tests that Wrangler can correctly resolve and bundle server-side dependencies -import { sum } from 'server-side-dep'; - -export function load() { - return { - sum: sum(1, 2) - }; -} diff --git a/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.svelte b/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.svelte deleted file mode 100644 index d5e339683387..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/src/routes/+page.svelte +++ /dev/null @@ -1,5 +0,0 @@ - - -

Sum: {data.sum}

diff --git a/packages/adapter-cloudflare/test/apps/pages/test/test.js b/packages/adapter-cloudflare/test/apps/pages/test/test.js deleted file mode 100644 index 0619c030bbc2..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/test/test.js +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@playwright/test'; - -test('worker', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toContainText('Sum: 3'); -}); diff --git a/packages/adapter-cloudflare/test/apps/pages/tsconfig.json b/packages/adapter-cloudflare/test/apps/pages/tsconfig.json deleted file mode 100644 index 0c2092500732..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "allowJs": true, - "checkJs": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "sourceMap": true, - "moduleResolution": "bundler" - }, - "extends": "$app/tsconfig" -} diff --git a/packages/adapter-cloudflare/test/apps/pages/vite.config.js b/packages/adapter-cloudflare/test/apps/pages/vite.config.js deleted file mode 100644 index 01b9947e7d2a..000000000000 --- a/packages/adapter-cloudflare/test/apps/pages/vite.config.js +++ /dev/null @@ -1,12 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import adapter from '../../../index.js'; - -/** @type {import('vite').UserConfig} */ -const config = { - build: { - minify: false - }, - plugins: [sveltekit({ adapter: adapter() })] -}; - -export default config; From 590d6e8f14eaaeea004431b4a47c025cdd6a9b85 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:59:09 +0800 Subject: [PATCH 03/12] changeset --- .changeset/fancy-flies-brake.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fancy-flies-brake.md diff --git a/.changeset/fancy-flies-brake.md b/.changeset/fancy-flies-brake.md new file mode 100644 index 000000000000..e230223fb9d6 --- /dev/null +++ b/.changeset/fancy-flies-brake.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-cloudflare': major +--- + +breaking: remove support for Cloudflare Pages From 6867668928db034b3f0d542319cffdfa64f8ee20 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:59:13 +0800 Subject: [PATCH 04/12] Update package.json --- packages/adapter-cloudflare/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index 9dab338e32e9..15d86b5f8d81 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -1,7 +1,7 @@ { "name": "@sveltejs/adapter-cloudflare", "version": "8.0.0-next.3", - "description": "Adapts SvelteKit applications for Cloudflare Workers or Cloudflare Pages", + "description": "Adapts SvelteKit applications for Cloudflare Workers", "keywords": [ "adapter", "cloudflare pages", From e8c662dd49fc60b732327480d6a50a3e98bd5e7b Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:59:26 +0800 Subject: [PATCH 05/12] Update README.md --- packages/adapter-cloudflare/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-cloudflare/README.md b/packages/adapter-cloudflare/README.md index fb8ce1266e61..9bb5b787272a 100644 --- a/packages/adapter-cloudflare/README.md +++ b/packages/adapter-cloudflare/README.md @@ -1,6 +1,6 @@ # adapter-cloudflare -[Adapter](https://svelte.dev/docs/kit/building-your-app) for building SvelteKit applications on [Cloudflare Workers](https://developers.cloudflare.com/workers/) with [static assets](https://developers.cloudflare.com/workers/static-assets/) or [Cloudflare Pages](https://developers.cloudflare.com/pages/) with [Workers integration](https://developers.cloudflare.com/pages/functions/). +[Adapter](https://svelte.dev/docs/kit/building-your-app) for building SvelteKit applications on [Cloudflare Workers](https://developers.cloudflare.com/workers/) with [static assets](https://developers.cloudflare.com/workers/static-assets/). ## Docs From e567b4f783f8424779d9e25c1d51165298a4466b Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 04:59:39 +0800 Subject: [PATCH 06/12] Update package.json --- packages/adapter-cloudflare/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-cloudflare/package.json b/packages/adapter-cloudflare/package.json index 15d86b5f8d81..cd4ea242c1d7 100644 --- a/packages/adapter-cloudflare/package.json +++ b/packages/adapter-cloudflare/package.json @@ -4,7 +4,7 @@ "description": "Adapts SvelteKit applications for Cloudflare Workers", "keywords": [ "adapter", - "cloudflare pages", + "cloudflare workers", "deploy", "hosting", "svelte", From a313d2466a413b3fe78842d0568d0646b6909c81 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 05:03:33 +0800 Subject: [PATCH 07/12] auto install with adapter auto although it will fail on build without a wrangler.jsonc file --- .../docs/25-build-and-deploy/60-adapter-cloudflare.md | 2 ++ packages/adapter-auto/adapters.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md index 083954adfd8c..9ddfb628d871 100644 --- a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md +++ b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md @@ -4,6 +4,8 @@ title: Cloudflare To deploy to [Cloudflare Workers](https://workers.cloudflare.com/), use [`adapter-cloudflare`](https://github.com/sveltejs/kit/tree/main/packages/adapter-cloudflare). +This adapter will be installed by default when you use [`adapter-auto`](adapter-auto). If you plan on staying with Cloudflare, you can switch from [`adapter-auto`](adapter-auto) to using this adapter directly so that `event.platform` is emulated during local development, type declarations are automatically applied, and the ability to set Cloudflare-specific options is provided. + ## Comparisons - `adapter-cloudflare` – supports all SvelteKit features; builds for Cloudflare Workers Static Assets diff --git a/packages/adapter-auto/adapters.js b/packages/adapter-auto/adapters.js index 78deb2a87aa8..c95e27c50706 100644 --- a/packages/adapter-auto/adapters.js +++ b/packages/adapter-auto/adapters.js @@ -10,8 +10,8 @@ export const adapters = [ version: '7' }, { - name: 'Cloudflare Pages', - test: () => !!process.env.CF_PAGES, + name: 'Cloudflare Workers', + test: () => !!process.env.WORKERS_CI, module: '@sveltejs/adapter-cloudflare', version: '8' }, From e725f5928d03720617629429078621f08b727aff Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 05:06:56 +0800 Subject: [PATCH 08/12] Update index.js --- packages/adapter-cloudflare/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index 6d4a8f370a40..793a231d2bfd 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -48,7 +48,7 @@ export default function (options = {}) { } if (wrangler_config.assets?.directory) { // wrangler doesn't resolve `assets.directory` to an absolute path unlike - // `main` and `pages_build_output_dir` so we need to do it ourselves here + // `main` so we need to do it ourselves here const parent_dir = wrangler_config.configPath ? path.dirname(path.resolve(wrangler_config.configPath)) : process.cwd(); @@ -71,9 +71,9 @@ export default function (options = {}) { const assets_dest = `${dest}${builder.config.kit.paths.base}`; builder.mkdirp(assets_dest); if (wrangler_config.assets?.not_found_handling === '404-page') { - // generate plaintext 404.html first which can then be overridden by prerendering, if the user defined such a page. + // generate plaintext 404.html first which can then be overridden by + // prerendering, if the user defined such a page. // This file is served when a request fails to match an asset. - // If we're building for Cloudflare Pages, it's only served when a request matches an entry in `routes.exclude` const fallback = path.join(assets_dest, '404.html'); if (options.fallback === 'spa') { await builder.generateFallback(fallback); From ad15b72dfb0664ed0bd58d6ad98e92888b66fe86 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 05:07:38 +0800 Subject: [PATCH 09/12] Update pnpm-lock.yaml --- pnpm-lock.yaml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ef91f2258c1b..e4c1b13b7af2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -175,27 +175,6 @@ importers: specifier: 'catalog:' version: 4.1.10(@opentelemetry/api@1.9.0)(@types/node@22.19.19)(@vitest/browser-playwright@4.1.10)(jsdom@29.1.1)(vite@8.1.5(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.4.2)(yaml@2.9.0)) - packages/adapter-cloudflare/test/apps/pages: - devDependencies: - '@sveltejs/kit': - specifier: workspace:^ - version: link:../../../../kit - '@sveltejs/vite-plugin-svelte': - specifier: 'catalog:' - version: 7.0.0(svelte@5.56.3(@typescript-eslint/types@8.61.1))(vite@8.1.5(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.4.2)(yaml@2.9.0)) - server-side-dep: - specifier: file:server-side-dep - version: file:packages/adapter-cloudflare/test/apps/pages/server-side-dep - svelte: - specifier: 'catalog:' - version: 5.56.3(@typescript-eslint/types@8.61.1) - vite: - specifier: 'catalog:' - version: 8.1.5(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.4.2)(yaml@2.9.0) - wrangler: - specifier: 'catalog:' - version: 4.103.0(@cloudflare/workers-types@4.20260621.1) - packages/adapter-cloudflare/test/apps/workers: devDependencies: '@sveltejs/kit': @@ -3829,9 +3808,6 @@ packages: engines: {node: '>=10'} hasBin: true - server-side-dep@file:packages/adapter-cloudflare/test/apps/pages/server-side-dep: - resolution: {directory: packages/adapter-cloudflare/test/apps/pages/server-side-dep, type: directory} - server-side-dep@file:packages/adapter-cloudflare/test/apps/workers/server-side-dep: resolution: {directory: packages/adapter-cloudflare/test/apps/workers/server-side-dep, type: directory} @@ -6437,8 +6413,6 @@ snapshots: semver@7.8.5: {} - server-side-dep@file:packages/adapter-cloudflare/test/apps/pages/server-side-dep: {} - server-side-dep@file:packages/adapter-cloudflare/test/apps/workers/server-side-dep: {} sharp@0.34.5: From bca9807b0b8abcb4161ff583d255a4d20ae5f8c6 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Sat, 1 Aug 2026 18:39:33 +0800 Subject: [PATCH 10/12] changeset --- .changeset/eager-poets-battle.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/eager-poets-battle.md diff --git a/.changeset/eager-poets-battle.md b/.changeset/eager-poets-battle.md new file mode 100644 index 000000000000..c1d990efb66a --- /dev/null +++ b/.changeset/eager-poets-battle.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-auto': major +--- + +breaking: install `@sveltejs/adapter-cloudflare` only when building on Cloudflare Worker Builds From 8c88f2877c6c9651e8d999b5240aa34656898671 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Sun, 2 Aug 2026 07:27:47 +0800 Subject: [PATCH 11/12] Update .changeset/eager-poets-battle.md Co-authored-by: Nic Polumeyv --- .changeset/eager-poets-battle.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/eager-poets-battle.md b/.changeset/eager-poets-battle.md index c1d990efb66a..07d7afb8d36b 100644 --- a/.changeset/eager-poets-battle.md +++ b/.changeset/eager-poets-battle.md @@ -2,4 +2,4 @@ '@sveltejs/adapter-auto': major --- -breaking: install `@sveltejs/adapter-cloudflare` only when building on Cloudflare Worker Builds +breaking: install `@sveltejs/adapter-cloudflare` only when building on Cloudflare Workers Builds From 2138166848da32e6cbba90dabe6daf898dba3de6 Mon Sep 17 00:00:00 2001 From: Tee Ming Date: Sun, 2 Aug 2026 07:28:34 +0800 Subject: [PATCH 12/12] Update packages/adapter-cloudflare/index.js Co-authored-by: Nic Polumeyv --- packages/adapter-cloudflare/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index 793a231d2bfd..4858b9f26298 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -146,7 +146,7 @@ export default function (options = {}) { /** @type {App.Platform} */ const platform = { env: proxy.env, - // @ts-expect-error cloudflare type discrepencies + // @ts-expect-error cloudflare type discrepancies ctx: proxy.ctx, context: proxy.ctx, // deprecated in favor of ctx caches: proxy.caches,