diff --git a/.changeset/plenty-cougars-wave.md b/.changeset/plenty-cougars-wave.md new file mode 100644 index 000000000000..8bee172655e1 --- /dev/null +++ b/.changeset/plenty-cougars-wave.md @@ -0,0 +1,6 @@ +--- +'@sveltejs/adapter-cloudflare': minor +'@sveltejs/adapter-auto': minor +--- + +feat: support Cloudflare Workers Builds by detecting the `WORKERS_CI` environment variable 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 b078b25ee4fa..ada5f4f3932b 100644 --- a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md +++ b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md @@ -54,13 +54,11 @@ 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 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. +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. @@ -88,7 +86,7 @@ When building for Cloudflare Workers, this adapter expects to find a [Wrangler c { "name": "", "main": ".svelte-kit/cloudflare/_worker.js", - "compatibility_date": "2025-01-01", + "compatibility_date": "", "assets": { "binding": "ASSETS", "directory": ".svelte-kit/cloudflare", @@ -98,7 +96,7 @@ When building for Cloudflare Workers, this adapter expects to find a [Wrangler c ### Deployment -Please follow the [framework guide](https://developers.cloudflare.com/workers/frameworks/framework-guides/svelte/) for Cloudflare Workers to begin. +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 diff --git a/packages/adapter-auto/adapters.js b/packages/adapter-auto/adapters.js index 94fe1417ec73..f859ce3dd859 100644 --- a/packages/adapter-auto/adapters.js +++ b/packages/adapter-auto/adapters.js @@ -11,7 +11,7 @@ export const adapters = [ }, { name: 'Cloudflare Pages', - test: () => !!process.env.CF_PAGES, + test: () => !!process.env.WORKERS_CI || !!process.env.CF_PAGES, module: '@sveltejs/adapter-cloudflare', version: '7' }, diff --git a/packages/adapter-auto/index.js b/packages/adapter-auto/index.js index c83ba6246c59..659eab39bf05 100644 --- a/packages/adapter-auto/index.js +++ b/packages/adapter-auto/index.js @@ -84,7 +84,7 @@ async function get_adapter() { console.log(`Successfully installed ${match.module}.`); console.warn( - `\nIf you plan on staying on this deployment platform, consider replacing @sveltejs/adapter-auto with ${match.module}. This will give you faster and more robust installs, and more control over deployment configuration.\n` + `\nIf you plan on staying on this deployment platform, consider replacing @sveltejs/adapter-auto with ${match.module}. This will give you faster installs and more control over deployment configuration.\n` ); } catch (e) { throw new Error( diff --git a/packages/adapter-cloudflare/index.d.ts b/packages/adapter-cloudflare/index.d.ts index 0c02fb786cee..52ab26dafd11 100644 --- a/packages/adapter-cloudflare/index.d.ts +++ b/packages/adapter-cloudflare/index.d.ts @@ -19,7 +19,7 @@ export interface AdapterOptions { * 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. + * `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. diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index af99452ef8fd..4c4caa878195 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -27,8 +27,7 @@ export default function (options = {}) { ); } - const wrangler_config = validate_config(options.config); - const building_for_cloudflare_pages = is_building_for_cloudflare_pages(wrangler_config); + const { wrangler_config, building_for_cloudflare_pages } = validate_config(options.config); let dest = builder.getBuildDirectory('cloudflare'); let worker_dest = `${dest}/_worker.js`; @@ -95,9 +94,11 @@ export default function (options = {}) { 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 - SERVER: `${posixify(path.relative(worker_dest_dir, builder.getServerDirectory()))}/index.js`, - MANIFEST: `${posixify(path.relative(worker_dest_dir, tmp))}/manifest.js`, + // 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 } }); @@ -266,38 +267,58 @@ _redirects /** * @param {string} config_file - * @returns {import('wrangler').Unstable_Config} + * @returns {{ + * wrangler_config: import('wrangler').Unstable_Config, + * building_for_cloudflare_pages: boolean + * }} */ function validate_config(config_file = undefined) { const wrangler_config = unstable_readConfig({ config: config_file }); - // we don't support workers sites + const wrangler_file = wrangler_config.configPath || 'your wrangler.jsonc file'; + + // we don't support Workers Sites if (wrangler_config.site) { throw new Error( - `You must remove all \`site\` keys in ${wrangler_config.configPath}. Consult https://svelte.dev/docs/kit/adapter-cloudflare#Migrating-from-Workers-Sites-to-Workers-Static-Assets` + `You must remove all \`site\` keys in ${wrangler_file}. Consult https://svelte.dev/docs/kit/adapter-cloudflare#Migrating-from-Workers-Sites-to-Workers-Static-Assets` ); } - if (is_building_for_cloudflare_pages(wrangler_config)) { - return 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 + const building_for_cloudflare_pages = is_building_for_cloudflare_pages(wrangler_config); + if (building_for_cloudflare_pages) { + return { + wrangler_config, + building_for_cloudflare_pages + }; } - // probably deploying to Cloudflare Workers - if (wrangler_config.main || wrangler_config.assets) { - if (!wrangler_config.assets?.directory) { - throw new Error( - `You must specify the \`assets.directory\` key in ${wrangler_config.configPath}. Consult https://developers.cloudflare.com/workers/static-assets/binding/#directory` - ); - } + if ( + !wrangler_config.main && + wrangler_config.assets?.not_found_handling !== 'single-page-application' + ) { + throw new Error( + `You must specify the \`main\` key in ${wrangler_file} to deploy a Worker script. Consult https://developers.cloudflare.com/workers/wrangler/configuration/#inheritable-keys` + ); + } - if (!wrangler_config.assets?.binding) { - throw new Error( - `You must specify the \`assets.binding\` key in ${wrangler_config.configPath}. Consult https://developers.cloudflare.com/workers/static-assets/binding/#binding` - ); - } + if (!wrangler_config.assets?.directory) { + throw new Error( + `You must specify the \`assets.directory\` key in ${wrangler_file} to upload static assets. Consult https://developers.cloudflare.com/workers/static-assets/binding/#directory` + ); + } + + if (wrangler_config.main && !wrangler_config.assets?.binding) { + throw new Error( + `You must specify the \`assets.binding\` key in ${wrangler_file} when deploying a Worker script. Consult https://developers.cloudflare.com/workers/static-assets/binding/#binding` + ); } - return wrangler_config; + return { + wrangler_config, + building_for_cloudflare_pages + }; } /** @@ -305,13 +326,10 @@ function validate_config(config_file = undefined) { * @returns {boolean} */ function is_building_for_cloudflare_pages(wrangler_config) { - return ( - !!process.env.CF_PAGES || - !wrangler_config.configPath || - !!wrangler_config.pages_build_output_dir || - !wrangler_config.main || - !wrangler_config.assets - ); + if (!!process.env.WORKERS_CI || wrangler_config.main || wrangler_config.assets) { + return false; + } + return true; } /** @param {string} str */