From f9327cb85705748b99ae6f54f44a7f6d62a5ed37 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 12 Aug 2025 15:47:58 -0400 Subject: [PATCH 1/4] breaking: require `nodejs_als` compatibility flag --- .changeset/true-places-make.md | 5 ++++ .../60-adapter-cloudflare.md | 27 +++++++++++-------- packages/adapter-cloudflare/index.js | 17 ++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 .changeset/true-places-make.md diff --git a/.changeset/true-places-make.md b/.changeset/true-places-make.md new file mode 100644 index 000000000000..6920f7c4acd6 --- /dev/null +++ b/.changeset/true-places-make.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-cloudflare': major +--- + +breaking: require `nodejs_als` compatibility flag 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 1d5ae3974745..09a68b86f14e 100644 --- a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md +++ b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md @@ -89,6 +89,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_flags": ["nodejs_als"], "assets": { "binding": "ASSETS", "directory": ".svelte-kit/cloudflare", @@ -102,6 +103,8 @@ Please follow the [framework guide](https://developers.cloudflare.com/workers/fr ## Cloudflare Pages +Ensure that you have enabled the `nodejs_als` compatibility flag in your dashboard, or via your Wrangler configuration. + ### Deployment Please follow the [Get Started Guide](https://developers.cloudflare.com/pages/get-started/) for Cloudflare Pages to begin. @@ -120,6 +123,19 @@ You may wish to refer to [Cloudflare's documentation for deploying a SvelteKit s 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/). +## Node compatibility + +SvelteKit uses the [`AsyncLocalStorage`](https://nodejs.org/api/async_context.html#class-asynclocalstorage) API internally. You need to enable the `nodejs_als` [compatibility flag](https://developers.cloudflare.com/workers/runtime-apis/nodejs/), either via the Cloudflare dashboard (if using Pages) or your Wrangler configuration, or your app may break in production. + +```jsonc +/// file: wrangler.jsonc +{ + "compatibility_flags": ["nodejs_compat"] +} +``` + +If you app makes use of other Node.js APIs such as `node:path`, enable support via the `nodejs_compat` compatibility flag instead. + ## Runtime APIs The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/workers/runtime-apis/bindings/), which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`ctx`](https://developers.cloudflare.com/workers/runtime-apis/context/), [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/), and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#incomingrequestcfproperties), meaning that you can access it in hooks and endpoints: @@ -167,17 +183,6 @@ However, they will have no effect on responses dynamically rendered by SvelteKit ## Troubleshooting -### Node.js compatibility - -If you would like to enable [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/), you can add the `nodejs_compat` compatibility flag to your Wrangler configuration file: - -```jsonc -/// file: wrangler.jsonc -{ - "compatibility_flags": ["nodejs_compat"] -} -``` - ### Worker size limits When deploying your application, the server generated by SvelteKit is bundled into a single file. Wrangler will fail to publish your worker if it exceeds [the size limits](https://developers.cloudflare.com/workers/platform/limits/#worker-size) after minification. You're unlikely to hit this limit usually, but some large libraries can cause this to happen. In that case, you can try to reduce the size of your worker by only importing such libraries on the client side. See [the FAQ](./faq#How-do-I-use-a-client-side-library-accessing-document-or-window) for more information. diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index fdbdf9a769ed..5e79816a997d 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -34,6 +34,23 @@ export default function (options = {}) { const wrangler_config = validate_wrangler_config(options.config); + if ( + !wrangler_config?.compatibility_flags.includes('nodejs_compat') && + !wrangler_config?.compatibility_flags.includes('nodejs_als') + ) { + const file = wrangler_config.configPath + ? path.relative(process.cwd(), wrangler_config.configPath) + : 'your wrangler configuration'; + + throw new Error( + `\u001B\u001B[31m` + + `\nPlease add the "nodejs_als" compatibility flag to ${file}, as SvelteKit uses the AsyncLocalStorage API and your app may break in production without it.\n\n` + + `Alternatively, if you are using Node APIs in your app, you should add the "nodejs_compat" flag.\n\n` + + `For more information on compatibility flags see https://svelte.dev/docs/kit/adapter-cloudflare#Node-compatibility.\n` + + `\u001B[39m\u001B` + ); + } + const building_for_cloudflare_pages = is_building_for_cloudflare_pages(wrangler_config); let dest = builder.getBuildDirectory('cloudflare'); From 6593c378ea7da89dbc5e44b622bd198bf27d3921 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 12 Aug 2025 15:59:23 -0400 Subject: [PATCH 2/4] put it alongside other validation code --- packages/adapter-cloudflare/index.js | 34 +++++++++---------- .../test/apps/pages/wrangler.jsonc | 3 ++ .../test/apps/workers/wrangler.jsonc | 3 ++ 3 files changed, 23 insertions(+), 17 deletions(-) create mode 100644 packages/adapter-cloudflare/test/apps/pages/wrangler.jsonc create mode 100644 packages/adapter-cloudflare/test/apps/workers/wrangler.jsonc diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index 5e79816a997d..832ce41dc0bd 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -34,23 +34,6 @@ export default function (options = {}) { const wrangler_config = validate_wrangler_config(options.config); - if ( - !wrangler_config?.compatibility_flags.includes('nodejs_compat') && - !wrangler_config?.compatibility_flags.includes('nodejs_als') - ) { - const file = wrangler_config.configPath - ? path.relative(process.cwd(), wrangler_config.configPath) - : 'your wrangler configuration'; - - throw new Error( - `\u001B\u001B[31m` + - `\nPlease add the "nodejs_als" compatibility flag to ${file}, as SvelteKit uses the AsyncLocalStorage API and your app may break in production without it.\n\n` + - `Alternatively, if you are using Node APIs in your app, you should add the "nodejs_compat" flag.\n\n` + - `For more information on compatibility flags see https://svelte.dev/docs/kit/adapter-cloudflare#Node-compatibility.\n` + - `\u001B[39m\u001B` - ); - } - const building_for_cloudflare_pages = is_building_for_cloudflare_pages(wrangler_config); let dest = builder.getBuildDirectory('cloudflare'); @@ -318,6 +301,23 @@ function validate_wrangler_config(config_file = undefined) { validate_worker_settings(wrangler_config); } + if ( + !wrangler_config?.compatibility_flags.includes('nodejs_compat') && + !wrangler_config?.compatibility_flags.includes('nodejs_als') + ) { + const file = config_file + ? path.relative(process.cwd(), config_file) + : 'your wrangler configuration'; + + throw new Error( + `\u001B\u001B[31m` + + `\nPlease add the "nodejs_als" compatibility flag to ${file}, as SvelteKit uses the AsyncLocalStorage API and your app may break in production without it.\n\n` + + `Alternatively, if you are using Node APIs in your app, you should add the "nodejs_compat" flag.\n\n` + + `For more information on compatibility flags see https://svelte.dev/docs/kit/adapter-cloudflare#Node-compatibility.\n` + + `\u001B[39m\u001B` + ); + } + return wrangler_config; } diff --git a/packages/adapter-cloudflare/test/apps/pages/wrangler.jsonc b/packages/adapter-cloudflare/test/apps/pages/wrangler.jsonc new file mode 100644 index 000000000000..4f9e4671c786 --- /dev/null +++ b/packages/adapter-cloudflare/test/apps/pages/wrangler.jsonc @@ -0,0 +1,3 @@ +{ + "compatibility_flags": ["nodejs_als"] +} diff --git a/packages/adapter-cloudflare/test/apps/workers/wrangler.jsonc b/packages/adapter-cloudflare/test/apps/workers/wrangler.jsonc new file mode 100644 index 000000000000..4f9e4671c786 --- /dev/null +++ b/packages/adapter-cloudflare/test/apps/workers/wrangler.jsonc @@ -0,0 +1,3 @@ +{ + "compatibility_flags": ["nodejs_als"] +} From 0d764a5f755b4541b2f5ed1b671a5f717b391239 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 12 Aug 2025 15:59:59 -0400 Subject: [PATCH 3/4] tweak --- packages/adapter-cloudflare/index.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index 832ce41dc0bd..ebc438c718ad 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -301,10 +301,9 @@ function validate_wrangler_config(config_file = undefined) { validate_worker_settings(wrangler_config); } - if ( - !wrangler_config?.compatibility_flags.includes('nodejs_compat') && - !wrangler_config?.compatibility_flags.includes('nodejs_als') - ) { + const flags = wrangler_config?.compatibility_flags ?? []; + + if (flags.includes('nodejs_compat') && flags.includes('nodejs_als')) { const file = config_file ? path.relative(process.cwd(), config_file) : 'your wrangler configuration'; From 2c7b63d0512c8e8816c718da870e56f5cfddbc0a Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 12 Aug 2025 17:22:39 -0400 Subject: [PATCH 4/4] Update documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md Co-authored-by: Ben McCann <322311+benmccann@users.noreply.github.com> --- documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 09a68b86f14e..63aa28e0447f 100644 --- a/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md +++ b/documentation/docs/25-build-and-deploy/60-adapter-cloudflare.md @@ -130,7 +130,7 @@ SvelteKit uses the [`AsyncLocalStorage`](https://nodejs.org/api/async_context.ht ```jsonc /// file: wrangler.jsonc { - "compatibility_flags": ["nodejs_compat"] + "compatibility_flags": ["nodejs_als"] } ```