Skip to content

Commit

Permalink
Overhaul adapter API (#2931)
Browse files Browse the repository at this point in the history
* start fiddling about with code-split server code

* generate build data

* working, minus adapters

* prerendering

* WIP

* tidy some stuff up

* fix prefixes

* adapter-node working

* tidy up

* tidy

* make copy opts optional

* tidy

* netlify working albeit with single function

* expose route data to adapters

* some progress

* lint

* remove sandbox example from PR

* implement createEntries API

* fix some tests

* AMP fix

* tests all passing

* update gitignore

* disable adapter-node tests for now

* typechecking

* always create prerendered output directory

* manifest -> generateManifest, add utils-level method

* spread -> rest

* finesse return value of copy helper

* no need to pass config through to adapter

* Update packages/kit/src/core/build/index.js

Co-authored-by: Ben McCann <[email protected]>

* fix

* refactor out method extraction

* add comment to resolve separate routes/components entry point detection

* remove out of date comment

* nicer rollup output types

* actually that caused chaos, doing this instead

* fix tests

* update adapter-cloudflare

* refactor build functions into client/server/service worker modules

* make build_server more readable

* oops

* gah

* windows fix

* split manifest into public and private parts, so we can use manifest.assets in adapters

* lint

* prevent duplication of asset list in functions

* exclude prerendered pages from functions

* lint

* get vercel adapter working (with v1 filesystem API)

* target node14

* rename utils -> builder

* add methods for getting directories instead of hardcoding .svelte-kit etc

* fix lockfile

* update cloudflare adapters

* update readmes

* tidy up

* tweak docs

* remove sandbox from workspace

* try pinning version

* Update packages/kit/src/core/build/build_server.js

Co-authored-by: Ben McCann <[email protected]>

* remove redundant strict fs stuff

* remove sandbox from gitignore

* lint

* fix cloudflare pages handling of prerendered pages

* support esm and cjs manifests

* force createEntries to follow prerender

* fix types

* fix adapter-netlify

* separate App from InternalApp

* Update packages/kit/types/internal.d.ts

Co-authored-by: Ben McCann <[email protected]>

* expose SSRManifest

* fall back to HTTP fetch if endpoint is missing

* app.render should not be passed a host string

* default hostHeader to host in config

* fix types

* replace page.host with page.origin

* fix host stuff

* make SSR route splitting optional

* simplify createEntries

* these are no longer generic

* implement .json heuristic

* lint

* changesets

* changeset

* Update packages/adapter-netlify/index.js

Co-authored-by: Ben McCann <[email protected]>

* Update packages/adapter-node/README.md

Co-authored-by: Ben McCann <[email protected]>

* this.server -> this.vite

* give a bare-bones description of createEntries

* lint

* add missing origin

* remove TODO

* replace ts-ignore with ts-expect-error

* Update packages/kit/src/core/adapt/builder.js

Co-authored-by: Ben McCann <[email protected]>

* document AdapterEntry

* Update packages/kit/types/config.d.ts

Co-authored-by: Ben McCann <[email protected]>

* oops

* manifest -> vite_manifest

Co-authored-by: Ben McCann <[email protected]>
Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
3 people authored Dec 29, 2021
1 parent 588aaaf commit ecb423b
Show file tree
Hide file tree
Showing 110 changed files with 2,345 additions and 1,761 deletions.
12 changes: 12 additions & 0 deletions .changeset/clean-camels-pump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@sveltejs/adapter-auto': patch
'@sveltejs/adapter-cloudflare': patch
'@sveltejs/adapter-cloudflare-workers': patch
'@sveltejs/adapter-netlify': patch
'@sveltejs/adapter-node': patch
'@sveltejs/adapter-static': patch
'@sveltejs/adapter-vercel': patch
'@sveltejs/kit': patch
---

Overhaul adapter API
7 changes: 7 additions & 0 deletions .changeset/early-snakes-peel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@sveltejs/adapter-cloudflare': patch
'@sveltejs/adapter-cloudflare-workers': patch
'@sveltejs/adapter-vercel': patch
---

Remove esbuild options
5 changes: 5 additions & 0 deletions .changeset/fresh-years-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Replace config.kit.hostHeader with config.kit.headers.host, add config.kit.headers.protocol
5 changes: 5 additions & 0 deletions .changeset/fuzzy-forks-worry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Replace page.host with page.origin
5 changes: 5 additions & 0 deletions .changeset/smart-deers-approve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-netlify': patch
---

Add experimental function splitting
6 changes: 6 additions & 0 deletions .changeset/tiny-singers-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/adapter-netlify': patch
'@sveltejs/adapter-node': patch
---

Don't bundle final output
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v2
- uses: pnpm/[email protected]
with:
version: 6
version: 6.23.2
- uses: actions/setup-node@v2
with:
node-version: '14.x'
Expand All @@ -41,7 +41,7 @@ jobs:
- uses: actions/checkout@v2
- uses: pnpm/[email protected]
with:
version: 6
version: 6.23.2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
Expand Down Expand Up @@ -75,7 +75,7 @@ jobs:
- uses: actions/checkout@v2
- uses: pnpm/[email protected]
with:
version: 6
version: 6.23.2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
fetch-depth: 0
- uses: pnpm/[email protected]
with:
version: 6
version: 6.23.2
- name: Setup Node.js 12.x
uses: actions/setup-node@v2
with:
Expand Down
4 changes: 2 additions & 2 deletions documentation/docs/01-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ type RequestHeaders = Record<string, string>;
export type RawBody = null | Uint8Array;
export interface IncomingRequest {
method: string;
host: string;
path: string;
query: URLSearchParams;
headers: RequestHeaders;
Expand All @@ -72,6 +71,7 @@ type ParameterizedBody<Body = unknown> = Body extends FormData
// ServerRequest is exported as Request
export interface ServerRequest<Locals = Record<string, any>, Body = unknown>
extends IncomingRequest {
origin: string;
params: Record<string, string>;
body: ParameterizedBody<Body>;
locals: Locals; // populated by hooks handle
Expand All @@ -96,7 +96,7 @@ export interface RequestHandler<
}
```

For example, our hypothetical blog page, `/blog/cool-article`, might request data from `/blog/cool-article.json`, which could be represented by a `src/routes/blog/[slug].json.js` endpoint:
For example, our hypothetical blog page, `/blog/cool-article`, might request data from `/blog/cool-article.json`, which could be represented by a `src/routes/blog/[slug].json.js` endpoint:

```js
import db from '$lib/database';
Expand Down
6 changes: 3 additions & 3 deletions documentation/docs/03-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface LoadInput<
Session = any
> {
page: {
host: string;
origin: string;
path: string;
params: PageParams;
query: URLSearchParams;
Expand Down Expand Up @@ -92,11 +92,11 @@ The `load` function receives an object containing four fields — `page`, `fetch

#### page

`page` is a `{ host, path, params, query }` object where `host` is the URL's host, `path` is its pathname, `params` is derived from `path` and the route filename, and `query` is an instance of [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). Mutating `page` does not update the current URL; you should instead navigate using [`goto`](#modules-$app-navigation).
`page` is an `{ origin, path, params, query }` object where `origin` is the URL's origin, `path` is its pathname, `params` is derived from `path` and the route filename, and `query` is an instance of [`URLSearchParams`](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams). Mutating `page` does not update the current URL; you should instead navigate using [`goto`](#modules-$app-navigation).

So if the example above was `src/routes/blog/[slug].svelte` and the URL was `https://example.com/blog/some-post?foo=bar&baz&bizz=a&bizz=b`, the following would be true:

- `page.host === 'example.com'`
- `page.origin === 'https://example.com'`
- `page.path === '/blog/some-post'`
- `page.params.slug === 'some-post'`
- `page.query.get('foo') === 'bar'`
Expand Down
2 changes: 1 addition & 1 deletion documentation/docs/04-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type RequestHeaders = Record<string, string>;
export type RawBody = null | Uint8Array;
export interface IncomingRequest {
method: string;
host: string;
path: string;
query: URLSearchParams;
headers: RequestHeaders;
Expand All @@ -39,6 +38,7 @@ type ParameterizedBody<Body = unknown> = Body extends FormData
// ServerRequest is exported as Request
export interface ServerRequest<Locals = Record<string, any>, Body = unknown>
extends IncomingRequest {
origin: string;
params: Record<string, string>;
body: ParameterizedBody<Body>;
locals: Locals; // populated by hooks handle
Expand Down
10 changes: 5 additions & 5 deletions documentation/docs/05-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Because of that, the stores are not free-floating objects: they must be accessed
The stores themselves attach to the correct context at the point of subscription, which means you can import and use them directly in components without boilerplate. However, it still needs to be called synchronously on component or page initialisation when `$`-prefix isn't used. Use `getStores` to safely `.subscribe` asynchronously instead.

- `navigating` is a [readable store](https://svelte.dev/tutorial/readable-stores). When navigating starts, its value is `{ from, to }`, where `from` and `to` both mirror the `page` store value. When navigating finishes, its value reverts to `null`.
- `page` is a readable store whose value reflects the object passed to `load` functions — it contains `host`, `path`, `params` and `query`. See the [`page` section](#loading-input-page) above for more details.
- `page` is a readable store whose value reflects the object passed to `load` functions — it contains `origin`, `path`, `params` and `query`. See the [`page` section](#loading-input-page) above for more details.
- `session` is a [writable store](https://svelte.dev/tutorial/writable-stores) whose initial value is whatever was returned from [`getSession`](#hooks-getsession). It can be written to, but this will _not_ cause changes to persist on the server — this is something you must implement yourself.

### $lib
Expand All @@ -84,12 +84,12 @@ This module provides a helper function to sequence multiple `handle` calls.
import { sequence } from '@sveltejs/kit/hooks';

async function first({ request, resolve }) {
console.log('first');
return await resolve(request);
console.log('first');
return await resolve(request);
}
async function second({ request, resolve }) {
console.log('second');
return await resolve(request);
console.log('second');
return await resolve(request);
}

export const handle = sequence(first, second);
Expand Down
12 changes: 6 additions & 6 deletions documentation/docs/10-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default function (options) {
/** @type {import('@sveltejs/kit').Adapter} */
return {
name: 'adapter-package-name',
async adapt({ utils, config }) {
async adapt(builder) {
// adapter implementation
}
};
Expand All @@ -88,15 +88,15 @@ The types for `Adapter` and its parameters are available in [types/config.d.ts](
Within the `adapt` method, there are a number of things that an adapter should do:

- Clear out the build directory
- Call `builder.prerender({ dest })` to prerender pages
- Output code that:
- Imports `init` and `render` from `.svelte-kit/output/server/app.js`
- Calls `init`, which configures the app
- Imports `App` from `${builder.getServerDirectory()}/app.js`
- Instantiates the app with a manifest generated with `builder.generateManifest({ relativePath })`
- Listens for requests from the platform, converts them to a a [SvelteKit request](#hooks-handle), calls the `render` function to generate a [SvelteKit response](#hooks-handle) and responds with it
- Globally shims `fetch` to work on the target platform, if necessary. SvelteKit provides a `@sveltejs/kit/install-fetch` helper for platforms that can use `node-fetch`
- Bundle the output to avoid needing to install dependencies on the target platform, if desired
- Call `utils.prerender`
- Bundle the output to avoid needing to install dependencies on the target platform, if necessary
- Put the user's static files and the generated JS/CSS in the correct location for the target platform

If possible, we recommend putting the adapter output under the `build/` directory with any intermediate output placed under `.svelte-kit/[adapter-name]`.
Where possible, we recommend putting the adapter output under the `build/` directory with any intermediate output placed under `.svelte-kit/[adapter-name]`.

> The adapter API may change before 1.0.
27 changes: 20 additions & 7 deletions documentation/docs/14-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,11 @@ const config = {
template: 'src/app.html'
},
floc: false,
headers: {
host: null,
protocol: null
},
host: null,
hostHeader: null,
hydrate: true,
package: {
dir: 'package',
Expand All @@ -47,6 +50,7 @@ const config = {
entries: ['*'],
onError: 'fail'
},
protocol: null,
router: true,
serviceWorker: {
register: true,
Expand Down Expand Up @@ -103,25 +107,30 @@ Permissions-Policy: interest-cohort=()

> This only applies to server-rendered responses — headers for prerendered pages (e.g. created with [adapter-static](https://github.com/sveltejs/kit/tree/master/packages/adapter-static)) are determined by the hosting platform.
### host

A value that overrides the `Host` header when populating `page.host`
### headers

### hostHeader
The [`page.origin`] property is derived from the request protocol (normally `https`) and the host, which is taken from the `Host` header by default.

If your app is behind a reverse proxy (think load balancers and CDNs) then the `Host` header will be incorrect. In most cases, the underlying host is exposed via the [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) header and you should specify this in your config if you need to access `page.host`:
If your app is behind a reverse proxy (think load balancers and CDNs) then the `Host` header will be incorrect. In most cases, the underlying protocol and host are exposed via the [`X-Forwarded-Host`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host) and [`X-Forwarded-Proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) headers, which can be specified in your config:

```js
// svelte.config.js
export default {
kit: {
hostHeader: 'X-Forwarded-Host'
headers: {
host: 'X-Forwarded-Host',
protocol: 'X-Forwarded-Proto'
}
}
};
```

**You should only do this if you trust the reverse proxy**, which is why it isn't the default.

### host

A value that overrides the one derived from [`config.kit.headers.host`](#configuration-headers-host).

### hydrate

Whether to [hydrate](#ssr-and-javascript-hydrate) the server-rendered HTML with a client-side app. (It's rare that you would set this to `false` on an app-wide basis.)
Expand Down Expand Up @@ -194,6 +203,10 @@ See [Prerendering](#ssr-and-javascript-prerender). An object containing zero or
};
```

### protocol

The protocol is assumed to be `'https'` (unless you're developing locally without the `--https` flag) unless [`config.kit.headers.protocol`](#configuration-headers-protocol) is set. If necessary, you can override it here.

### router

Enables or disables the client-side [router](#ssr-and-javascript-router) app-wide.
Expand Down
10 changes: 4 additions & 6 deletions packages/adapter-auto/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,10 @@ export default function () {
return {
name: '@sveltejs/adapter-auto',

async adapt(options) {
async adapt(builder) {
for (const candidate of adapters) {
if (candidate.test()) {
options.utils.log.info(
`Detected environment: ${candidate.name}. Using ${candidate.module}`
);
builder.log.info(`Detected environment: ${candidate.name}. Using ${candidate.module}`);

let module;

Expand All @@ -30,11 +28,11 @@ export default function () {
}

const adapter = module.default();
return adapter.adapt(options);
return adapter.adapt(builder);
}
}

options.utils.log.warn(
builder.log.warn(
'Could not detect a supported production environment. See https://kit.svelte.dev/docs#adapters to learn how to configure your app to run on the platform of your choosing'
);
}
Expand Down
33 changes: 0 additions & 33 deletions packages/adapter-cloudflare-workers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

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

This is very experimental; the adapter API isn't at all fleshed out, and things will definitely change.

_**Comparisons**_

- `adapter-cloudflare` – supports all SvelteKit features; builds for
Expand Down Expand Up @@ -86,37 +84,6 @@ npm run build && wrangler publish

More info on configuring a cloudflare worker site can be found [here](https://developers.cloudflare.com/workers/platform/sites/start-from-existing)

## Advanced Configuration

### esbuild

As an escape hatch, you may optionally specify a function which will receive the final esbuild options generated by this adapter and returns a modified esbuild configuration. The result of this function will be passed as-is to esbuild. The function can be async.

For example, you may wish to add a plugin:

```js
adapterCfw({
esbuild(options) {
return {
...options,
plugins: []
};
}
});
```

The default options for this version are as follows:

```js
const options = {
entryPoints: ['.svelte-kit/cloudflare-workers/entry.js'],
outfile: `${entrypoint}/index.js`,
bundle: true,
target: 'es2020',
platform: 'browser'
};
```

## Changelog

[The Changelog for this package is available on GitHub](https://github.com/sveltejs/kit/blob/master/packages/adapter-cloudflare-workers/CHANGELOG.md).
9 changes: 4 additions & 5 deletions packages/adapter-cloudflare-workers/files/entry.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// TODO hardcoding the relative location makes this brittle
import { init, render } from '../output/server/app.js';
import { App } from 'APP';
import { manifest } from './manifest.js';
import { getAssetFromKV, NotFoundError } from '@cloudflare/kv-asset-handler';

init();
const app = new App(manifest);

addEventListener('fetch', (event) => {
event.respondWith(handle(event));
Expand All @@ -29,8 +29,7 @@ async function handle(event) {
const request_url = new URL(request.url);

try {
const rendered = await render({
host: request_url.host,
const rendered = await app.render({
path: request_url.pathname,
query: request_url.searchParams,
rawBody: await read(request),
Expand Down
7 changes: 1 addition & 6 deletions packages/adapter-cloudflare-workers/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import { Adapter } from '@sveltejs/kit';
import { BuildOptions } from 'esbuild';

interface AdapterOptions {
esbuild?: (options: BuildOptions) => Promise<BuildOptions> | BuildOptions;
}

declare function plugin(options?: AdapterOptions): Adapter;
declare function plugin(): Adapter;
export = plugin;
Loading

0 comments on commit ecb423b

Please sign in to comment.