Skip to content

Commit

Permalink
Allow passing platform context from adapters (#3429)
Browse files Browse the repository at this point in the history
* Can pass locals at app.render

* Updated cloudflare workers to pass in env to locals

* Fixed other adapters for new API

* Fixed naming in app types to be more consistent

* Updated to use meta in stead of polluting locals

* updated adapter cloudflare to use meta

* Added changesets

* Formated and linted

* Updated types to include Meta consistently

* Updated documentation to include information about the meta object

* Fixed type issue in hooks

* Updated naming to platform

* Added a way to get the original request from the node adapter

* Made platform Readonly in RequestEvent

* Fixed typo in docs

* Update documentation/docs/01-routing.md

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

* Fixed bad spaces

* Fixed merge issues

* rerun flakey tests

* rerun flakey tests 2

* Update documentation/docs/10-adapters.md grammer

Co-authored-by: Andrew McGrath <[email protected]>

* rerun flakey tests 3

* rerun flakey tests 4

* Changed node handler to pass in `req`
Added documentation to Node adaptor

* Updated cloudflare readme

* Renamed to request

* Use Record<string, any>

* rerun flakey tests 5

* change API to app.render(request, opts)

* update adapters

* use platform.req instead of platform.request — more idiomatic

* remove changesets for unaffected adapters

* tweak changesets

* remove platform stuff from routing section

* tweak adapter docs

* Fix documentation/docs/04-hooks.md spaces

Co-authored-by: Conduitry <[email protected]>

* remove changes to adapter-node

* create-svelte is unchanged

* simplify docs

Co-authored-by: Rich Harris <[email protected]>
Co-authored-by: Ben McCann <[email protected]>
Co-authored-by: Ignatius Bagus <[email protected]>
Co-authored-by: Andrew McGrath <[email protected]>
Co-authored-by: Rich Harris <[email protected]>
Co-authored-by: Conduitry <[email protected]>
  • Loading branch information
7 people authored Jan 27, 2022
1 parent b7ca4cf commit 667bc81
Show file tree
Hide file tree
Showing 13 changed files with 87 additions and 29 deletions.
5 changes: 5 additions & 0 deletions .changeset/cyan-numbers-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/adapter-cloudflare': patch
---

Pass `env` object to SvelteKit via `platform`
5 changes: 5 additions & 0 deletions .changeset/many-mayflies-clap.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

Allow adapters to pass in `platform` object
12 changes: 9 additions & 3 deletions documentation/docs/01-routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,12 @@ Endpoints are modules written in `.js` (or `.ts`) files that export functions co
// Declaration types for Endpoints
// * declarations that are not exported are for internal use

export interface RequestEvent<Locals = Record<string, any>> {
export interface RequestEvent<Locals = Record<string, any>, Platform = Record<string, any>> {
request: Request;
url: URL;
params: Record<string, string>;
locals: Locals;
platform: Platform;
}

type Body = JSONString | Uint8Array | ReadableStream | stream.Readable;
Expand All @@ -69,8 +70,13 @@ type MaybePromise<T> = T | Promise<T>;
interface Fallthrough {
fallthrough: true;
}
export interface RequestHandler<Locals = Record<string, any>, Output extends Body = Body> {
(event: RequestEvent<Locals>): MaybePromise<

export interface RequestHandler<
Locals = Record<string, any>,
Platform = Record<string, any>,
Output extends Body = Body
> {
(event: RequestEvent<Locals, Platform>): MaybePromise<
Either<Response | EndpointOutput<Output>, Fallthrough>
>;
}
Expand Down
21 changes: 13 additions & 8 deletions documentation/docs/04-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,22 @@ If unimplemented, defaults to `({ event, resolve }) => resolve(event)`.
// everything else must be a type of string
type ResponseHeaders = Record<string, string | string[]>;

export interface RequestEvent<Locals = Record<string, any>> {
export interface RequestEvent<Locals = Record<string, any>, Platform = Record<string, any>> {
request: Request;
url: URL;
params: Record<string, string>;
locals: Locals;
platform: Platform;
}

export interface ResolveOpts {
ssr?: boolean;
}

export interface Handle<Locals = Record<string, any>> {
export interface Handle<Locals = Record<string, any>, Platform = Record<string, any>> {
(input: {
event: RequestEvent<Locals>;
resolve(event: RequestEvent<Locals>, opts?: ResolveOpts): MaybePromise<Response>;
event: RequestEvent<Locals, Platform>;
resolve(event: RequestEvent<Locals, Platform>, opts?: ResolveOpts): MaybePromise<Response>;
}): MaybePromise<Response>;
}
```
Expand Down Expand Up @@ -84,8 +85,8 @@ If unimplemented, SvelteKit will log the error with default formatting.

```ts
// Declaration types for handleError hook
export interface HandleError<Locals = Record<string, any>> {
(input: { error: Error & { frame?: string }; event: RequestEvent<Locals> }): void;
export interface HandleError<Locals = Record<string, any>, Platform = Record<string, any>> {
(input: { error: Error & { frame?: string }; event: RequestEvent<Locals, Platform> }): void;
}
```

Expand All @@ -107,8 +108,12 @@ If unimplemented, session is `{}`.

```ts
// Declaration types for getSession hook
export interface GetSession<Locals = Record<string, any>, Session = any> {
(event: RequestEvent<Locals>): Session | Promise<Session>;
export interface GetSession<
Locals = Record<string, any>,
Platform = Record<string, any>,
Session = any
> {
(event: RequestEvent<Locals, Platform>): MaybePromise<Session>;
}
```

Expand Down
5 changes: 5 additions & 0 deletions documentation/docs/10-adapters.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ Most adapters will generate static HTML for any [prerenderable](#page-options-pr

You can also use `adapter-static` to generate single-page apps (SPAs) by specifying a [fallback page](https://github.com/sveltejs/kit/tree/master/packages/adapter-static#spa-mode).

#### Platform-specific context

Some adapters may have access to additional information about the request. For example, Cloudflare Workers can access an `env` object containing KV namespaces etc. This can be passed to the `RequestEvent` used in [hooks](#hooks) and [endpoints](#routing-endpoints) as the `platform` property — consult each adapter's documentation to learn more.

### Community adapters

Additional [community-provided adapters](https://sveltesociety.dev/components#adapters) exist for other platforms. After installing the relevant adapter with your package manager, update your `svelte.config.js`:
Expand Down Expand Up @@ -93,6 +97,7 @@ Within the `adapt` method, there are a number of things that an adapter should d
- 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 standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) if necessary, calls the `render` function to generate a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) and responds with it
- expose any platform-specific information to SvelteKit via the `platform` option passed to `app.render`
- 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 necessary
- Put the user's static files and the generated JS/CSS in the correct location for the target platform
Expand Down
20 changes: 20 additions & 0 deletions packages/adapter-cloudflare/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ When configuring your project settings, you must use the following settings:

> **Important:** You need to add a `NODE_VERSION` environment variable to both the "production" and "preview" environments. You can add this during project setup or later in the Pages project settings. SvelteKit requires Node `14.13` or later, so you should use `14` or `16` as the `NODE_VERSION` value.
## Environment variables

The [`env`](https://developers.cloudflare.com/workers/runtime-apis/fetch-event#parameters) object, containing KV namespaces etc, is passed to SvelteKit via the `platform` property, meaning you can access it in hooks and endpoints:

```ts
interface Locals {}

interface Platform {
env: {
COUNTER: DurableObjectNamespace;
};
}

export async function post<Locals, Platform>({ request, platform }) {
const counter = platform.env.COUNTER.idFromName('A');
}
```

> `platform.env` is only available in the production build. Use [wrangler](https://developers.cloudflare.com/workers/cli-wrangler) to test it locally
## Changelog

[The Changelog for this package is available on GitHub](https://github.com/sveltejs/kit/blob/master/packages/adapter-cloudflare/CHANGELOG.md).
2 changes: 1 addition & 1 deletion packages/adapter-cloudflare/files/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {

// dynamically-generated pages
try {
return await app.render(req);
return await app.render(req, { platform: { env } });
} catch (e) {
return new Response('Error rendering route: ' + (e.message || e.toString()), { status: 500 });
}
Expand Down
7 changes: 2 additions & 5 deletions packages/kit/src/core/build/build_server.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,12 @@ export class App {
};
}
render(request, {
prerender
} = {}) {
render(request, options = {}) {
if (!(request instanceof Request)) {
throw new Error('The first argument to app.render must be a Request object. See https://github.com/sveltejs/kit/pull/3384 for details');
}
return respond(request, this.options, { prerender });
return respond(request, this.options, options);
}
}
`;
Expand Down Expand Up @@ -172,7 +170,6 @@ export async function build_server(
return relative_file[0] === '.' ? relative_file : `./${relative_file}`;
};

// prettier-ignore
fs.writeFileSync(
input.app,
app_template({
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/src/runtime/server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export async function respond(request, options, state = {}) {
request,
url,
params: {},
locals: {}
locals: {},
platform: state.platform
};

// TODO remove this for 1.0
Expand Down
10 changes: 7 additions & 3 deletions packages/kit/types/app.d.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import { PrerenderOptions, SSRNodeLoader, SSRRoute } from './internal';

export interface RequestOptions<Platform = Record<string, any>> {
platform?: Platform;
}

export class App {
constructor(manifest: SSRManifest);
render(request: Request): Promise<Response>;
render(request: Request, options?: RequestOptions): Promise<Response>;
}

export class InternalApp extends App {
render(
request: Request,
options?: {
prerender: PrerenderOptions;
options?: RequestOptions & {
prerender?: PrerenderOptions;
}
): Promise<Response>;
}
Expand Down
8 changes: 6 additions & 2 deletions packages/kit/types/endpoint.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ export interface Fallthrough {
fallthrough: true;
}

export interface RequestHandler<Locals = Record<string, any>, Output extends Body = Body> {
(event: RequestEvent<Locals>): MaybePromise<
export interface RequestHandler<
Locals = Record<string, any>,
Platform = Record<string, any>,
Output extends Body = Body
> {
(event: RequestEvent<Locals, Platform>): MaybePromise<
Either<Response | EndpointOutput<Output>, Fallthrough>
>;
}
17 changes: 11 additions & 6 deletions packages/kit/types/hooks.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@ import { MaybePromise } from './helper';

export type StrictBody = string | Uint8Array;

export interface RequestEvent<Locals = Record<string, any>> {
export interface RequestEvent<Locals = Record<string, any>, Platform = Record<string, any>> {
request: Request;
url: URL;
params: Record<string, string>;
locals: Locals;
platform: Readonly<Platform>;
}

export interface GetSession<Locals = Record<string, any>, Session = any> {
(event: RequestEvent<Locals>): MaybePromise<Session>;
export interface GetSession<
Locals = Record<string, any>,
Platform = Record<string, any>,
Session = any
> {
(event: RequestEvent<Locals, Platform>): MaybePromise<Session>;
}

export interface ResolveOpts {
ssr?: boolean;
}

export interface Handle<Locals = Record<string, any>> {
export interface Handle<Locals = Record<string, any>, Platform = Record<string, any>> {
(input: {
event: RequestEvent<Locals>;
resolve(event: RequestEvent<Locals>, opts?: ResolveOpts): MaybePromise<Response>;
event: RequestEvent<Locals, Platform>;
resolve(event: RequestEvent<Locals, Platform>, opts?: ResolveOpts): MaybePromise<Response>;
}): MaybePromise<Response>;
}

Expand Down
1 change: 1 addition & 0 deletions packages/kit/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ export interface SSRRenderOptions {
export interface SSRRenderState {
fetched?: string;
initiator?: SSRPage | null;
platform?: any;
prerender?: PrerenderOptions;
fallback?: string;
}
Expand Down

0 comments on commit 667bc81

Please sign in to comment.