From 2406d7e7a2ad191024f0148b268c61254f1806ef Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2024 20:33:57 -0500 Subject: [PATCH 1/5] allow compatible node modules when targeting vercel edge functions --- packages/adapter-vercel/index.js | 70 ++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 683df1757073..c2cfdbd80093 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -18,6 +18,9 @@ const get_default_runtime = () => { ); }; +// https://vercel.com/docs/functions/edge-functions/edge-runtime#compatible-node.js-modules +const compatible_node_modules = ['async_hooks', 'events', 'buffer', 'assert', 'util']; + /** @type {import('.').default} **/ const plugin = function (defaults = {}) { if ('edge' in defaults) { @@ -109,20 +112,61 @@ const plugin = function (defaults = {}) { `export const manifest = ${builder.generateManifest({ relativePath, routes })};\n` ); - await esbuild.build({ - entryPoints: [`${tmp}/edge.js`], - outfile: `${dirs.functions}/${name}.func/index.js`, - target: 'es2020', // TODO verify what the edge runtime supports - bundle: true, - platform: 'browser', - format: 'esm', - external: config.external, - sourcemap: 'linked', - banner: { js: 'globalThis.global = globalThis;' }, - loader: { - '.wasm': 'copy' + try { + const result = await esbuild.build({ + entryPoints: [`${tmp}/edge.js`], + outfile: `${dirs.functions}/${name}.func/index.js`, + target: 'es2020', // TODO verify what the edge runtime supports + bundle: true, + platform: 'browser', + format: 'esm', + external: [ + ...compatible_node_modules, + ...compatible_node_modules.map((id) => `node:${id}`), + ...(config.external || []) + ], + sourcemap: 'linked', + banner: { js: 'globalThis.global = globalThis;' }, + loader: { + '.wasm': 'copy' + } + }); + + if (result.warnings.length > 0) { + const formatted = await esbuild.formatMessages(result.warnings, { + kind: 'warning', + color: true + }); + + console.error(formatted.join('\n')); } - }); + } catch (error) { + for (const e of error.errors) { + for (const node of e.notes) { + const match = + /The package "(.+)" wasn't found on the file system but is built into node/.exec( + node.text + ); + + if (match) { + node.text = `Cannot use "${match[1]}" when deploying to Vercel Edge Functions.`; + } + } + } + + const formatted = await esbuild.formatMessages(error.errors, { + kind: 'error', + color: true + }); + + console.error(formatted.join('\n')); + + throw new Error( + `Bundling with esbuild failed with ${error.errors.length} ${ + error.errors.length === 1 ? 'error' : 'errors' + }` + ); + } write( `${dirs.functions}/${name}.func/.vc-config.json`, From 1bdda28f309ab1cc9ca27ac5e6a0af0600f05aa8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2024 20:34:03 -0500 Subject: [PATCH 2/5] test --- sites/kit.svelte.dev/src/routes/delete-me/+server.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 sites/kit.svelte.dev/src/routes/delete-me/+server.js diff --git a/sites/kit.svelte.dev/src/routes/delete-me/+server.js b/sites/kit.svelte.dev/src/routes/delete-me/+server.js new file mode 100644 index 000000000000..bf616ab4beb8 --- /dev/null +++ b/sites/kit.svelte.dev/src/routes/delete-me/+server.js @@ -0,0 +1,11 @@ +import util from 'util'; + +export const prerender = false; + +export const config = { + runtime: 'edge' +}; + +export function GET() { + return new Response(util.inspect({ message: 'hello' })); +} From aefb7ca5a3419acbafb7f2e7613450148578531f Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2024 20:36:35 -0500 Subject: [PATCH 3/5] confirmed it works, deleting test case --- sites/kit.svelte.dev/src/routes/delete-me/+server.js | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 sites/kit.svelte.dev/src/routes/delete-me/+server.js diff --git a/sites/kit.svelte.dev/src/routes/delete-me/+server.js b/sites/kit.svelte.dev/src/routes/delete-me/+server.js deleted file mode 100644 index bf616ab4beb8..000000000000 --- a/sites/kit.svelte.dev/src/routes/delete-me/+server.js +++ /dev/null @@ -1,11 +0,0 @@ -import util from 'util'; - -export const prerender = false; - -export const config = { - runtime: 'edge' -}; - -export function GET() { - return new Response(util.inspect({ message: 'hello' })); -} From 97683f66844bd9f256b5faf1da1b72d3a5b48766 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2024 20:51:55 -0500 Subject: [PATCH 4/5] allow node built-ins when creating edge functions --- packages/adapter-netlify/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 767644efd892..7bfec980ef9a 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -1,6 +1,7 @@ import { appendFileSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'; import { dirname, join, resolve, posix } from 'node:path'; import { fileURLToPath } from 'node:url'; +import { builtinModules } from 'node:module'; import esbuild from 'esbuild'; import toml from '@iarna/toml'; @@ -165,7 +166,12 @@ async function generate_edge_functions({ builder }) { format: 'esm', platform: 'browser', sourcemap: 'linked', - target: 'es2020' + target: 'es2020', + + // Node built-ins are allowed, but must be prefixed with `node:` + // https://docs.netlify.com/edge-functions/api/#runtime-environment + external: builtinModules.map((id) => `node:${id}`), + alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`])) }); writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest)); From 81fd0916cb5c6bb85d3abd0709459e74bbeda8c8 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 18 Jan 2024 20:54:01 -0500 Subject: [PATCH 5/5] changesets --- .changeset/chatty-pandas-swim.md | 5 +++++ .changeset/two-pianos-obey.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/chatty-pandas-swim.md create mode 100644 .changeset/two-pianos-obey.md diff --git a/.changeset/chatty-pandas-swim.md b/.changeset/chatty-pandas-swim.md new file mode 100644 index 000000000000..5fa9bd5cecf0 --- /dev/null +++ b/.changeset/chatty-pandas-swim.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-vercel': minor +--- + +feat: allow compatible subset of Node.js built-in modules when targeting edge functions diff --git a/.changeset/two-pianos-obey.md b/.changeset/two-pianos-obey.md new file mode 100644 index 000000000000..1a5f50d810e4 --- /dev/null +++ b/.changeset/two-pianos-obey.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/adapter-netlify': minor +--- + +feat: allow Node.js built-in modules when targeting edge functions