Skip to content
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

feat: support unbundled deployments #13259

Draft
wants to merge 5 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
5 changes: 5 additions & 0 deletions .changeset/chatty-moons-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-cloudflare-workers': minor
---

feat: support unbundled deployments
53 changes: 53 additions & 0 deletions .changeset/smart-owls-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
'@sveltejs/adapter-cloudflare-workers': major
---

feat: use the new Workers Static Assets feature from Cloudflare

This changes the adapter to stop using the old Workers Sites (kv-asset-handler) approach.
Instead, making use of the new Workers Static Assets feature, which is embedded into Cloudflare natively.

Also this change removes the extra esbuild step that was being run inside the adapter, relying upon Wrangler to do the bundling.
The extra esbuild step required a hardcoded list of Node.js compatible modules.
This is no longer needed since Wrangler now manages all of that.

## Breaking changes and migration

- This version of the adapter requires Wrangler version 3.87.0 or later.

Run `npm add -D wrangler@latest` (or similar) in your project to update Wrangler.
- The user's Wrangler configuration (`wrangler.toml`) must be migrated from using Workers Sites to using Workers Assets.

Previously a user's `wrangler.toml` might look like:

```toml
name = "<your-site-name>"
account_id = "<your-account-id>"
compatibility_date = "2021-11-12"
main = "./.cloudflare/worker.js"

# Workers Sites configuration
site.bucket = "./.cloudflare/public"
```

Change it to to look like:

```toml
name = "<your-site-name>"
account_id = "<your-account-id>"
compatibility_date = "2021-11-12"`
main = ".svelte-kit/cloudflare/server/index.js"

# Workers Assets configuration
assets = { directory = ".svelte-kit/cloudflare/client" }
```

- Workers Assets defaults to serving assets directly for a matching request, rather than routing it through the Worker code.

The previous adapter would add custom headers to assets responses (such as `cache-control`, `content-type`, and `x-robots-tag`. Such direct asset responses no longer contain these headers - but the will include eTag headers that have proven (in Pages) to be an effective caching strategy for assets.

If you wish to always run the Worker before every request then add `serve_directly = false` to the assets configuration section. For example:

```toml
assets = { directory = ".svelte-kit/cloudflare/client", serve_directly = false }
```
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,18 @@ This adapter expects to find a [wrangler.toml/wrangler.json](https://developers.
```toml
/// file: wrangler.toml
name = "<your-service-name>"
account_id = "<your-account-id>"

main = "./.cloudflare/worker.js"
site.bucket = "./.cloudflare/public"
main = "./.cloudflare/server/worker.js"
assets = { directory = ".svelte-kit/cloudflare/client" }

build.command = "npm run build"

compatibility_date = "2021-11-12"
workers_dev = true
```

`<your-service-name>` can be anything. `<your-account-id>` can be found by logging into your [Cloudflare dashboard](https://dash.cloudflare.com) and grabbing it from the end of the URL:
`<your-service-name>` can be anything.

```
https://dash.cloudflare.com/<your-account-id>
```

> [!NOTE] You should add the `.cloudflare` directory (or whichever directories you specified for `main` and `site.bucket`) to your `.gitignore`.
> [!NOTE] You should add the `.cloudflare` directory (or whichever directories you specified for `main` and `assets`) to your `.gitignore`.

You will need to install [wrangler](https://developers.cloudflare.com/workers/wrangler/get-started/) and log in, if you haven't already:

Expand All @@ -83,13 +77,26 @@ wrangler deploy

If you would like to use a config file other than `wrangler.toml` you can specify so using the [`config` option](#Options-config).

If you would like to enable [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/#enable-nodejs-from-the-cloudflare-dashboard), you can add "nodejs_compat" flag to `wrangler.toml`:
If you would like to enable [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/#enable-nodejs-from-the-cloudflare-dashboard), you can add the "nodejs_compat" flag to `wrangler.toml`:

```toml
/// file: wrangler.toml
compatibility_flags = [ "nodejs_compat" ]
```

## Unbundled deployment

If you would like to deploy your worker [without bundling](https://developers.cloudflare.com/workers/wrangler/configuration/#bundling) it, you will need to add the following `rules` key to `wrangler.toml` so that the additional modules are included in your deployment.

```toml
/// file: wrangler.toml
rules = [
{ type = "ESModule", globs = ["**/*.js"] }
]
```

Finally, run `wrangler deploy --no-bundle` to prevent Wrangler from bundling your code.

## Runtime APIs

The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object contains your project's [bindings](https://developers.cloudflare.com/pages/platform/functions/bindings/), which consist of KV/DO namespaces, etc. It is passed to SvelteKit via the `platform` property, along with [`context`](https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/#contextwaituntil), [`caches`](https://developers.cloudflare.com/workers/runtime-apis/cache/), and [`cf`](https://developers.cloudflare.com/workers/runtime-apis/request/#the-cf-property-requestinitcfproperties), meaning that you can access it in hooks and endpoints:
Expand Down
2 changes: 1 addition & 1 deletion packages/adapter-cloudflare-workers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

SvelteKit adapter that creates a Cloudflare Workers site using a function for dynamic server rendering.

**Requires [Wrangler v2](https://developers.cloudflare.com/workers/wrangler/get-started/).** Wrangler v1 is no longer supported.
**Requires [Wrangler v3 or later](https://developers.cloudflare.com/workers/wrangler/get-started/).**.

## Docs

Expand Down
9 changes: 0 additions & 9 deletions packages/adapter-cloudflare-workers/files/_package.json

This file was deleted.

45 changes: 6 additions & 39 deletions packages/adapter-cloudflare-workers/files/entry.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { Server } from 'SERVER';
import { manifest, prerendered, base_path } from 'MANIFEST';
import { getAssetFromKV, mapRequestToAsset } from '@cloudflare/kv-asset-handler';
import static_asset_manifest_json from '__STATIC_CONTENT_MANIFEST';
const static_asset_manifest = JSON.parse(static_asset_manifest_json);

const server = new Server(manifest);

Expand All @@ -25,7 +22,7 @@ export default {
// static assets
if (url.pathname.startsWith(app_path)) {
/** @type {Response} */
const res = await get_asset_from_kv(req, env, context);
const res = await env.ASSETS.fetch(req);
if (is_error(res.status)) return res;

const cache_control = url.pathname.startsWith(immutable)
Expand Down Expand Up @@ -65,20 +62,11 @@ export default {

let location = pathname.at(-1) === '/' ? stripped_pathname : pathname + '/';

if (
is_static_asset ||
prerendered.has(pathname) ||
pathname === version_file ||
pathname.startsWith(immutable)
) {
return get_asset_from_kv(req, env, context, (request, options) => {
if (prerendered.has(pathname)) {
url.pathname = '/' + prerendered.get(pathname).file;
return new Request(url.toString(), request);
}

return mapRequestToAsset(request, options);
});
if (prerendered.has(pathname)) {
url.pathname = '/' + prerendered.get(pathname).file;
return env.ASSETS.fetch(new Request(url.toString(), req));
} else if (is_static_asset || pathname === version_file || pathname.startsWith(immutable)) {
return env.ASSETS.fetch(req);
} else if (location && prerendered.has(location)) {
if (search) location += search;
return new Response('', {
Expand Down Expand Up @@ -106,27 +94,6 @@ export default {
}
};

/**
* @param {Request} req
* @param {any} env
* @param {any} context
*/
async function get_asset_from_kv(req, env, context, map = mapRequestToAsset) {
return await getAssetFromKV(
{
request: req,
waitUntil(promise) {
return context.waitUntil(promise);
}
},
{
ASSET_NAMESPACE: env.__STATIC_CONTENT,
ASSET_MANIFEST: static_asset_manifest,
mapRequestToAsset: map
}
);
}

/**
* @param {number} status
* @returns {boolean}
Expand Down
Loading
Loading