summaryrefslogtreecommitdiff
path: root/packages/integrations/netlify/src
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@skypack.dev> 2022-04-19 11:22:15 -0400
committerGravatar GitHub <noreply@github.com> 2022-04-19 11:22:15 -0400
commit4cf54c60aa63bd614b242da0602790015005673d (patch)
tree25fcec1da64890044742a1090b1773076a0d43e9 /packages/integrations/netlify/src
parentc35e94f5443d4ade07ff787d39b042eb3b9004fb (diff)
downloadastro-4cf54c60aa63bd614b242da0602790015005673d.tar.gz
astro-4cf54c60aa63bd614b242da0602790015005673d.tar.zst
astro-4cf54c60aa63bd614b242da0602790015005673d.zip
Netlify Edge function support (#3148)
* Netlify Edge function support * Update readme with edge function information * Adds a changeset * Disable running edge function test in CI for now
Diffstat (limited to 'packages/integrations/netlify/src')
-rw-r--r--packages/integrations/netlify/src/README.md46
-rw-r--r--packages/integrations/netlify/src/edge-shim.ts4
-rw-r--r--packages/integrations/netlify/src/index.ts73
-rw-r--r--packages/integrations/netlify/src/integration-edge-functions.ts98
-rw-r--r--packages/integrations/netlify/src/integration-functions.ts66
-rw-r--r--packages/integrations/netlify/src/netlify-edge-functions.ts20
6 files changed, 195 insertions, 112 deletions
diff --git a/packages/integrations/netlify/src/README.md b/packages/integrations/netlify/src/README.md
deleted file mode 100644
index 1a77ed598..000000000
--- a/packages/integrations/netlify/src/README.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# @astrojs/netlify
-
-Deploy your server-side rendered (SSR) Astro app to [Netlify](https://www.netlify.com/).
-
-Use this adapter in your Astro configuration file, alongside a valid deployment URL:
-
-```js
-import { defineConfig } from 'astro/config';
-import netlify from '@astrojs/netlify/functions';
-
-export default defineConfig({
- adapter: netlify(),
-});
-```
-
-After you build your site the `netlify/` folder will contain [Netlify Functions](https://docs.netlify.com/functions/overview/) in the `netlify/functions/` folder.
-
-Now you can deploy!
-
-```shell
-netlify deploy
-```
-
-## Configuration
-
-### dist
-
-We build to a `netlify` directory at the base of your project. To change this, use the `dist` option:
-
-```js
-import { defineConfig } from 'astro/config';
-import netlify from '@astrojs/netlify/functions';
-
-export default defineConfig({
- adapter: netlify({
- dist: new URL('./dist/', import.meta.url)
- })
-});
-```
-
-And then point to the dist in your `netlify.toml`:
-
-```toml
-[functions]
- directory = "dist/functions"
-```
diff --git a/packages/integrations/netlify/src/edge-shim.ts b/packages/integrations/netlify/src/edge-shim.ts
new file mode 100644
index 000000000..1a4a6ee9b
--- /dev/null
+++ b/packages/integrations/netlify/src/edge-shim.ts
@@ -0,0 +1,4 @@
+(globalThis as any).process = {
+ argv: [],
+ env: {},
+};
diff --git a/packages/integrations/netlify/src/index.ts b/packages/integrations/netlify/src/index.ts
index c473de67a..121495652 100644
--- a/packages/integrations/netlify/src/index.ts
+++ b/packages/integrations/netlify/src/index.ts
@@ -1,65 +1,8 @@
-import type { AstroAdapter, AstroIntegration, AstroConfig } from 'astro';
-import fs from 'fs';
-
-export function getAdapter(): AstroAdapter {
- return {
- name: '@astrojs/netlify',
- serverEntrypoint: '@astrojs/netlify/netlify-functions.js',
- exports: ['handler'],
- args: {},
- };
-}
-
-interface NetlifyFunctionsOptions {
- dist?: URL;
-}
-
-function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegration {
- let _config: AstroConfig;
- let entryFile: string;
- return {
- name: '@astrojs/netlify',
- hooks: {
- 'astro:config:setup': ({ config }) => {
- if (dist) {
- config.outDir = dist;
- } else {
- config.outDir = new URL('./netlify/', config.root);
- }
- },
- 'astro:config:done': ({ config, setAdapter }) => {
- setAdapter(getAdapter());
- _config = config;
- },
- 'astro:build:start': async ({ buildConfig }) => {
- entryFile = buildConfig.serverEntry.replace(/\.m?js/, '');
- buildConfig.client = _config.outDir;
- buildConfig.server = new URL('./functions/', _config.outDir);
- },
- 'astro:build:done': async ({ routes, dir }) => {
- const _redirectsURL = new URL('./_redirects', dir);
-
- // Create the redirects file that is used for routing.
- let _redirects = '';
- for (const route of routes) {
- if (route.pathname) {
- _redirects += `
-${route.pathname} /.netlify/functions/${entryFile} 200`;
- } else {
- const pattern =
- '/' + route.segments.map(([part]) => (part.dynamic ? '*' : part.content)).join('/');
- _redirects += `
-${pattern} /.netlify/functions/${entryFile} 200`;
- }
- }
-
- // Always use appendFile() because the redirects file could already exist,
- // e.g. due to a `/public/_redirects` file that got copied to the output dir.
- // If the file does not exist yet, appendFile() automatically creates it.
- await fs.promises.appendFile(_redirectsURL, _redirects, 'utf-8');
- },
- },
- };
-}
-
-export { netlifyFunctions, netlifyFunctions as default };
+export {
+ netlifyFunctions,
+ netlifyFunctions as default
+} from './integration-functions.js';
+
+export {
+ netlifyEdgeFunctions
+} from './integration-edge-functions.js';
diff --git a/packages/integrations/netlify/src/integration-edge-functions.ts b/packages/integrations/netlify/src/integration-edge-functions.ts
new file mode 100644
index 000000000..fcce820f4
--- /dev/null
+++ b/packages/integrations/netlify/src/integration-edge-functions.ts
@@ -0,0 +1,98 @@
+import type { AstroAdapter, AstroIntegration, AstroConfig, RouteData } from 'astro';
+import * as fs from 'fs';
+
+export function getAdapter(): AstroAdapter {
+ return {
+ name: '@astrojs/netlify/edge-functions',
+ serverEntrypoint: '@astrojs/netlify/netlify-edge-functions.js',
+ exports: ['default'],
+ };
+}
+
+interface NetlifyEdgeFunctionsOptions {
+ dist?: URL;
+}
+
+interface NetlifyEdgeFunctionManifestFunctionPath {
+ function: string;
+ path: string;
+}
+
+interface NetlifyEdgeFunctionManifestFunctionPattern {
+ function: string;
+ pattern: string;
+}
+
+type NetlifyEdgeFunctionManifestFunction = NetlifyEdgeFunctionManifestFunctionPath | NetlifyEdgeFunctionManifestFunctionPattern;
+
+interface NetlifyEdgeFunctionManifest {
+ functions: NetlifyEdgeFunctionManifestFunction[];
+ version: 1;
+}
+
+async function createEdgeManifest(routes: RouteData[], entryFile: string, dir: URL) {
+ const functions: NetlifyEdgeFunctionManifestFunction[] = [];
+ for(const route of routes) {
+ if(route.pathname) {
+ functions.push({
+ function: entryFile,
+ path: route.pathname
+ });
+ } else {
+ functions.push({
+ function: entryFile,
+ pattern: route.pattern.source
+ });
+ }
+ }
+
+ const manifest: NetlifyEdgeFunctionManifest = {
+ functions,
+ version: 1
+ };
+
+ const manifestURL = new URL('./manifest.json', dir);
+ const _manifest = JSON.stringify(manifest, null, ' ');
+ await fs.promises.writeFile(manifestURL, _manifest, 'utf-8');
+}
+
+export function netlifyEdgeFunctions({ dist }: NetlifyEdgeFunctionsOptions = {}): AstroIntegration {
+ let _config: AstroConfig;
+ let entryFile: string;
+ return {
+ name: '@astrojs/netlify/edge-functions',
+ hooks: {
+ 'astro:config:setup': ({ config }) => {
+ if (dist) {
+ config.outDir = dist;
+ } else {
+ config.outDir = new URL('./netlify/', config.root);
+ }
+ },
+ 'astro:config:done': ({ config, setAdapter }) => {
+ setAdapter(getAdapter());
+ _config = config;
+ },
+ 'astro:build:start': async ({ buildConfig }) => {
+ entryFile = buildConfig.serverEntry.replace(/\.m?js/, '');
+ buildConfig.client = _config.outDir;
+ buildConfig.server = new URL('./edge-functions/', _config.outDir);
+ },
+ 'astro:build:setup': ({ vite, target }) => {
+ if (target === 'server') {
+ vite.ssr = {
+ noExternal: true,
+ };
+ }
+ },
+ 'astro:build:done': async ({ routes, dir }) => {
+
+ await createEdgeManifest(routes, entryFile, new URL('./edge-functions/', dir));
+ },
+ },
+ };
+}
+
+export {
+ netlifyEdgeFunctions as default
+}
diff --git a/packages/integrations/netlify/src/integration-functions.ts b/packages/integrations/netlify/src/integration-functions.ts
index 5b687cda4..2720eb591 100644
--- a/packages/integrations/netlify/src/integration-functions.ts
+++ b/packages/integrations/netlify/src/integration-functions.ts
@@ -1 +1,65 @@
-export { netlifyFunctions as default } from './index.js';
+import type { AstroAdapter, AstroIntegration, AstroConfig } from 'astro';
+import fs from 'fs';
+
+export function getAdapter(): AstroAdapter {
+ return {
+ name: '@astrojs/netlify/functions',
+ serverEntrypoint: '@astrojs/netlify/netlify-functions.js',
+ exports: ['handler'],
+ args: {},
+ };
+}
+
+interface NetlifyFunctionsOptions {
+ dist?: URL;
+}
+
+function netlifyFunctions({ dist }: NetlifyFunctionsOptions = {}): AstroIntegration {
+ let _config: AstroConfig;
+ let entryFile: string;
+ return {
+ name: '@astrojs/netlify',
+ hooks: {
+ 'astro:config:setup': ({ config }) => {
+ if (dist) {
+ config.outDir = dist;
+ } else {
+ config.outDir = new URL('./netlify/', config.root);
+ }
+ },
+ 'astro:config:done': ({ config, setAdapter }) => {
+ setAdapter(getAdapter());
+ _config = config;
+ },
+ 'astro:build:start': async ({ buildConfig }) => {
+ entryFile = buildConfig.serverEntry.replace(/\.m?js/, '');
+ buildConfig.client = _config.outDir;
+ buildConfig.server = new URL('./functions/', _config.outDir);
+ },
+ 'astro:build:done': async ({ routes, dir }) => {
+ const _redirectsURL = new URL('./_redirects', dir);
+
+ // Create the redirects file that is used for routing.
+ let _redirects = '';
+ for (const route of routes) {
+ if (route.pathname) {
+ _redirects += `
+${route.pathname} /.netlify/functions/${entryFile} 200`;
+ } else {
+ const pattern =
+ '/' + route.segments.map(([part]) => (part.dynamic ? '*' : part.content)).join('/');
+ _redirects += `
+${pattern} /.netlify/functions/${entryFile} 200`;
+ }
+ }
+
+ // Always use appendFile() because the redirects file could already exist,
+ // e.g. due to a `/public/_redirects` file that got copied to the output dir.
+ // If the file does not exist yet, appendFile() automatically creates it.
+ await fs.promises.appendFile(_redirectsURL, _redirects, 'utf-8');
+ },
+ },
+ };
+}
+
+export { netlifyFunctions, netlifyFunctions as default };
diff --git a/packages/integrations/netlify/src/netlify-edge-functions.ts b/packages/integrations/netlify/src/netlify-edge-functions.ts
new file mode 100644
index 000000000..f7000442c
--- /dev/null
+++ b/packages/integrations/netlify/src/netlify-edge-functions.ts
@@ -0,0 +1,20 @@
+import './edge-shim.js';
+import { SSRManifest } from 'astro';
+import { App } from 'astro/app';
+
+export function createExports(manifest: SSRManifest) {
+ const app = new App(manifest);
+
+ const handler = async (request: Request): Promise<Response> => {
+ if(app.match(request)) {
+ return app.render(request);
+ }
+
+ return new Response(null, {
+ status: 404,
+ statusText: 'Not found'
+ });
+ };
+
+ return { 'default': handler };
+}