Skip to content

feat: support Cloudflare Workers Builds #13733

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/plenty-cougars-wave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/adapter-cloudflare': minor
'@sveltejs/adapter-auto': minor
---

feat: support Cloudflare Workers Builds by detecting the `WORKERS_CI` environment variable
10 changes: 4 additions & 6 deletions documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -88,7 +86,7 @@ When building for Cloudflare Workers, this adapter expects to find a [Wrangler c
{
"name": "<any-name-you-want>",
"main": ".svelte-kit/cloudflare/_worker.js",
"compatibility_date": "2025-01-01",
"compatibility_date": "<YYYY-MM-DD>",
"assets": {
"binding": "ASSETS",
"directory": ".svelte-kit/cloudflare",
Expand All @@ -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

Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-auto/adapters.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
},
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-auto/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-cloudflare/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
78 changes: 48 additions & 30 deletions packages/adapter-cloudflare/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`;
Expand Down Expand Up @@ -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
}
});
Expand Down Expand Up @@ -266,52 +267,69 @@ _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
};
}

/**
* @param {import('wrangler').Unstable_Config} wrangler_config
* @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 */
Expand Down
Loading