feat(@astrojs/netlify): Add on-demand builders Netlify functions (#5874)

* Add on-demand builders option

* chore: add changeset

* docs: add documentation in configuration section

* Update packages/integrations/netlify/README.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update packages/integrations/netlify/README.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update packages/integrations/netlify/README.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update .changeset/twenty-pans-agree.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

---------

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
Juan Miguel Guerrero 2023-01-27 16:20:34 +01:00 committed by GitHub
parent 2565bc453e
commit 1c230f1037
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 40 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
'@astrojs/netlify': minor
---
Add `builders` config option for Netlify On-demand Builders.

View file

@ -117,6 +117,27 @@ And then point to the dist in your `netlify.toml`:
directory = "dist/functions" directory = "dist/functions"
``` ```
### builders
[Netlify On-demand Builders](https://docs.netlify.com/configure-builds/on-demand-builders/) are serverless functions used to build and cache page content on Netlifys Edge CDN. You can enable these functions with the `builders` option:
```js
// astro.config.mjs
import { defineConfig } from 'astro/config';
import netlify from '@astrojs/netlify/functions';
export default defineConfig({
output: 'server',
adapter: netlify({
builders: true
}),
});
```
On-demand Builders are only available with the `@astrojs/netlify/functions` adapter and are not compatible with Edge Functions.
### binaryMediaTypes ### binaryMediaTypes
> This option is only needed for the Functions adapter and is not needed for Edge Functions. > This option is only needed for the Functions adapter and is not needed for Edge Functions.

View file

@ -163,7 +163,7 @@ export function netlifyEdgeFunctions({ dist }: NetlifyEdgeFunctionsOptions = {})
'astro:build:done': async ({ routes, dir }) => { 'astro:build:done': async ({ routes, dir }) => {
await bundleServerEntry(_buildConfig, _vite); await bundleServerEntry(_buildConfig, _vite);
await createEdgeManifest(routes, entryFile, _config.root); await createEdgeManifest(routes, entryFile, _config.root);
await createRedirects(_config, routes, dir, entryFile, true); await createRedirects(_config, routes, dir, entryFile, 'edge-functions');
}, },
}, },
}; };

View file

@ -13,11 +13,13 @@ export function getAdapter(args: Args = {}): AstroAdapter {
interface NetlifyFunctionsOptions { interface NetlifyFunctionsOptions {
dist?: URL; dist?: URL;
builders?: boolean;
binaryMediaTypes?: string[]; binaryMediaTypes?: string[];
} }
function netlifyFunctions({ function netlifyFunctions({
dist, dist,
builders,
binaryMediaTypes, binaryMediaTypes,
}: NetlifyFunctionsOptions = {}): AstroIntegration { }: NetlifyFunctionsOptions = {}): AstroIntegration {
let _config: AstroConfig; let _config: AstroConfig;
@ -36,7 +38,7 @@ function netlifyFunctions({
}); });
}, },
'astro:config:done': ({ config, setAdapter }) => { 'astro:config:done': ({ config, setAdapter }) => {
setAdapter(getAdapter({ binaryMediaTypes })); setAdapter(getAdapter({ binaryMediaTypes, builders }));
_config = config; _config = config;
entryFile = config.build.serverEntry.replace(/\.m?js/, ''); entryFile = config.build.serverEntry.replace(/\.m?js/, '');
@ -48,7 +50,8 @@ function netlifyFunctions({
} }
}, },
'astro:build:done': async ({ routes, dir }) => { 'astro:build:done': async ({ routes, dir }) => {
await createRedirects(_config, routes, dir, entryFile, false); const type = builders ? 'builders' : 'functions'
await createRedirects(_config, routes, dir, entryFile, type);
}, },
}, },
}; };

View file

@ -1,5 +1,5 @@
import { polyfill } from '@astrojs/webapi'; import { polyfill } from '@astrojs/webapi';
import type { Handler } from '@netlify/functions'; import { builder, Handler } from '@netlify/functions';
import { SSRManifest } from 'astro'; import { SSRManifest } from 'astro';
import { App } from 'astro/app'; import { App } from 'astro/app';
@ -8,6 +8,7 @@ polyfill(globalThis, {
}); });
export interface Args { export interface Args {
builders?: boolean;
binaryMediaTypes?: string[]; binaryMediaTypes?: string[];
} }
@ -20,6 +21,7 @@ const clientAddressSymbol = Symbol.for('astro.clientAddress');
export const createExports = (manifest: SSRManifest, args: Args) => { export const createExports = (manifest: SSRManifest, args: Args) => {
const app = new App(manifest); const app = new App(manifest);
const builders = args.builders ?? false;
const binaryMediaTypes = args.binaryMediaTypes ?? []; const binaryMediaTypes = args.binaryMediaTypes ?? [];
const knownBinaryMediaTypes = new Set([ const knownBinaryMediaTypes = new Set([
'audio/3gpp', 'audio/3gpp',
@ -53,7 +55,7 @@ export const createExports = (manifest: SSRManifest, args: Args) => {
...binaryMediaTypes, ...binaryMediaTypes,
]); ]);
const handler: Handler = async (event) => { const myHandler: Handler = async (event) => {
const { httpMethod, headers, rawUrl, body: requestBody, isBase64Encoded } = event; const { httpMethod, headers, rawUrl, body: requestBody, isBase64Encoded } = event;
const init: RequestInit = { const init: RequestInit = {
method: httpMethod, method: httpMethod,
@ -143,6 +145,8 @@ export const createExports = (manifest: SSRManifest, args: Args) => {
return fnResponse; return fnResponse;
}; };
const handler = builders ? builder(myHandler) : myHandler
return { handler }; return { handler };
}; };

View file

@ -14,10 +14,10 @@ export async function createRedirects(
routes: RouteData[], routes: RouteData[],
dir: URL, dir: URL,
entryFile: string, entryFile: string,
edge: boolean type: 'functions' | 'edge-functions' | 'builders'
) { ) {
const _redirectsURL = new URL('./_redirects', dir); const _redirectsURL = new URL('./_redirects', dir);
const kind = edge ? 'edge-functions' : 'functions'; const kind = type ?? 'functions';
const definitions: RedirectDefinition[] = []; const definitions: RedirectDefinition[] = [];