diff --git a/.changeset/modern-scissors-shout.md b/.changeset/modern-scissors-shout.md new file mode 100644 index 000000000000..7d4b938db07d --- /dev/null +++ b/.changeset/modern-scissors-shout.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-netlify': minor +--- + +feat: configure edge function at route level diff --git a/documentation/docs/25-build-and-deploy/80-adapter-netlify.md b/documentation/docs/25-build-and-deploy/80-adapter-netlify.md index a9d5702b3b14..781d695652db 100644 --- a/documentation/docs/25-build-and-deploy/80-adapter-netlify.md +++ b/documentation/docs/25-build-and-deploy/80-adapter-netlify.md @@ -48,7 +48,22 @@ New projects will use the current Node LTS version by default. However, if you'r ## Netlify Edge Functions -SvelteKit supports [Netlify Edge Functions](https://docs.netlify.com/netlify-labs/experimental-features/edge-functions/). If you pass the option `edge: true` to the `adapter` function, server-side rendering will happen in a Deno-based edge function that's deployed close to the site visitor. If set to `false` (the default), the site will deploy to Node-based Netlify Functions. +SvelteKit supports [Netlify Edge Functions](https://docs.netlify.com/netlify-labs/experimental-features/edge-functions/). To control how your routes are deployed to Netlify as functions, you can export const config inside +server.js, +page(.server).js and +layout(.server).js files. + +For example you could deploy some parts of your app as Edge Functions... + +```js +// @errors: 2307 +/// file: about/+page.js +/** @type {import('@sveltejs/adapter-netlify').Config} */ +export const config = { + runtime: 'edge' +}; +``` + +...and others as Serverless Functions (note that by specifying config inside a layout, it applies to all child pages). + +If you pass the option `edge: true` to the `adapter` function, server-side rendering will happen in a Deno-based edge function that's deployed close to the site visitor for all pages. If set to `false` (the default), the site will deploy to Node-based Netlify Functions. ```js // @errors: 2307 diff --git a/packages/adapter-netlify/index.d.ts b/packages/adapter-netlify/index.d.ts index aef282740b2f..f14fd1bc1188 100644 --- a/packages/adapter-netlify/index.d.ts +++ b/packages/adapter-netlify/index.d.ts @@ -2,3 +2,11 @@ import { Adapter } from '@sveltejs/kit'; import './ambient.js'; export default function plugin(opts?: { split?: boolean; edge?: boolean }): Adapter; + +export interface Config { + /** + * Whether to use [Edge Functions](https://docs.netlify.com/edge-functions/overview/) (`'edge'`) + * @default undefined + */ + runtime?: 'edge'; +} diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 2b7fafd47711..1c8bd21d39cb 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -90,10 +90,29 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) { if (split) { throw new Error('Cannot use `split: true` alongside `edge: true`'); } + } + + /** @type {{ edge: import('@sveltejs/kit').RouteDefinition[], lambda: import('@sveltejs/kit').RouteDefinition[] }} */ + const mutated_routes = { edge: [], lambda: [] }; + for (let i = 0; i < builder.routes.length; i++) { + /** @type {import('@sveltejs/kit').RouteDefinition} */ + const route = builder.routes[i]; + + if (route.config?.runtime === 'edge') { + mutated_routes.edge.push(route); + } else { + mutated_routes.lambda.push(route); + } + } + if (mutated_routes.edge.length) { + builder.routes = mutated_routes.edge; await generate_edge_functions({ builder }); - } else { - generate_lambda_functions({ builder, split, publish }); + } + + if (mutated_routes.lambda.length) { + builder.routes = mutated_routes.lambda; + generate_lambda_functions({ builder, publish, split }); } }, @@ -204,7 +223,10 @@ function generate_lambda_functions({ builder, publish, split }) { builder.copy(`${files}/esm`, '.netlify', { replace }); // Configuring the function to use ESM as the output format. - const fn_config = JSON.stringify({ config: { nodeModuleFormat: 'esm' }, version: 1 }); + const fn_config = JSON.stringify({ + config: { nodeModuleFormat: 'esm' }, + version: 1 + }); builder.log.minor('Generating serverless functions...');