diff --git a/.changeset/yellow-clouds-kick.md b/.changeset/yellow-clouds-kick.md new file mode 100644 index 000000000000..0f4ede5f50fd --- /dev/null +++ b/.changeset/yellow-clouds-kick.md @@ -0,0 +1,7 @@ +--- +'@sveltejs/adapter-cloudflare': minor +'@sveltejs/adapter-netlify': minor +'@sveltejs/adapter-vercel': minor +--- + +feat: Add back esbuild argument to adapter configuration diff --git a/packages/adapter-cloudflare/index.d.ts b/packages/adapter-cloudflare/index.d.ts index e6fb925ff102..868e1bd25c69 100644 --- a/packages/adapter-cloudflare/index.d.ts +++ b/packages/adapter-cloudflare/index.d.ts @@ -1,8 +1,25 @@ import { Adapter } from '@sveltejs/kit'; +import { BuildOptions } from 'esbuild'; import './ambient.js'; export default function plugin(options?: AdapterOptions): Adapter; +interface DefaultEsbuildOptions { + platform: 'browser'; + conditions: ['worker', 'browser']; + sourcemap: 'linked'; + target: 'es2022'; + entryPoints: [string]; + outfile: string; + allowOverwrite: true; + format: 'esm'; + bundle: true; +} + +type esbuild = ( + defaultOptions: DefaultEsbuildOptions +) => Required> & Partial; + export interface AdapterOptions { /** * Customize the automatically-generated `_routes.json` file @@ -30,6 +47,8 @@ export interface AdapterOptions { */ exclude?: string[]; }; + + esbuild?: esbuild; } export interface RoutesJSONSpec { diff --git a/packages/adapter-cloudflare/index.js b/packages/adapter-cloudflare/index.js index 4baec66be4c0..0fe8031f615c 100644 --- a/packages/adapter-cloudflare/index.js +++ b/packages/adapter-cloudflare/index.js @@ -45,7 +45,8 @@ export default function (options = {}) { } }); - await esbuild.build({ + /** @type { import('.').DefaultEsbuildOptions } */ + const default_bundler_props = { platform: 'browser', conditions: ['worker', 'browser'], sourcemap: 'linked', @@ -55,7 +56,13 @@ export default function (options = {}) { allowOverwrite: true, format: 'esm', bundle: true - }); + }; + + const bundler_props = options['esbuild'] + ? options['esbuild'](default_bundler_props) + : default_bundler_props; + + await esbuild.build(bundler_props); } }; } diff --git a/packages/adapter-netlify/index.d.ts b/packages/adapter-netlify/index.d.ts index aef282740b2f..b1745ff44c58 100644 --- a/packages/adapter-netlify/index.d.ts +++ b/packages/adapter-netlify/index.d.ts @@ -1,4 +1,23 @@ import { Adapter } from '@sveltejs/kit'; +import { BuildOptions } from 'esbuild'; import './ambient.js'; -export default function plugin(opts?: { split?: boolean; edge?: boolean }): Adapter; +interface DefaultEsbuildOptions { + entryPoints: [string]; + outfile: '.netlify/edge-functions/render.js'; + bundle: true; + format: 'esm'; + platform: 'browser'; + sourcemap: 'linked'; + target: 'es2020'; +} + +type esbuild = ( + defaultOptions: DefaultEsbuildOptions +) => Required> & Partial; + +export default function plugin(opts?: { + split?: boolean; + edge?: boolean; + esbuild?: esbuild; +}): Adapter; diff --git a/packages/adapter-netlify/index.js b/packages/adapter-netlify/index.js index 3307a730935e..ff981d800018 100644 --- a/packages/adapter-netlify/index.js +++ b/packages/adapter-netlify/index.js @@ -1,7 +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 esbuild from 'esbuild'; +import esbuild_bundler from 'esbuild'; import toml from '@iarna/toml'; /** @@ -36,7 +36,7 @@ const edge_set_in_env_var = const FUNCTION_PREFIX = 'sveltekit-'; /** @type {import('.').default} */ -export default function ({ split = false, edge = edge_set_in_env_var } = {}) { +export default function ({ split = false, edge = edge_set_in_env_var, esbuild = null } = {}) { return { name: '@sveltejs/adapter-netlify', @@ -88,7 +88,13 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) { throw new Error('Cannot use `split: true` alongside `edge: true`'); } - await generate_edge_functions({ builder }); + if (esbuild && typeof esbuild !== 'function') { + throw new Error( + `Type of esbuild must be a function if defined. Type provided ${typeof esbuild}` + ); + } + + await generate_edge_functions({ builder, esbuild_props: esbuild }); } else { await generate_lambda_functions({ builder, split, publish }); } @@ -98,8 +104,9 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) { /** * @param { object } params * @param {import('@sveltejs/kit').Builder} params.builder + * @param {import('.').esbuild} params.esbuild_props */ -async function generate_edge_functions({ builder }) { +async function generate_edge_functions({ builder, esbuild_props }) { const tmp = builder.getBuildDirectory('netlify-tmp'); builder.rimraf(tmp); builder.mkdirp(tmp); @@ -144,7 +151,8 @@ async function generate_edge_functions({ builder }) { )});\n` ); - await esbuild.build({ + /** @type { import('.').DefaultEsbuildOptions } */ + const default_bundler_props = { entryPoints: [`${tmp}/entry.js`], outfile: '.netlify/edge-functions/render.js', bundle: true, @@ -152,7 +160,13 @@ async function generate_edge_functions({ builder }) { platform: 'browser', sourcemap: 'linked', target: 'es2020' - }); + }; + + const bundler_props = esbuild_props + ? esbuild_props(default_bundler_props) + : default_bundler_props; + + await esbuild_bundler.build(bundler_props); writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest)); } diff --git a/packages/adapter-vercel/index.d.ts b/packages/adapter-vercel/index.d.ts index ea45bf4e0ac5..2c73576d5016 100644 --- a/packages/adapter-vercel/index.d.ts +++ b/packages/adapter-vercel/index.d.ts @@ -1,4 +1,5 @@ import { Adapter } from '@sveltejs/kit'; +import { BuildOptions } from 'esbuild'; import './ambient.js'; export default function plugin(config?: Config): Adapter; @@ -51,6 +52,22 @@ export interface ServerlessConfig { }; } +interface DefaultEsbuildOptions { + entryPoints: [string]; + outfile: string; + target: 'es2020'; + bundle: true; + platform: 'browser'; + format: 'esm'; + external?: string[]; + sourcemap: 'linked'; + banner: { js: 'globalThis.global = globalThis;' }; +} + +type esbuild = ( + defaultOptions: DefaultEsbuildOptions +) => Required> & Partial; + export interface EdgeConfig { /** * Whether to use [Edge Functions](https://vercel.com/docs/concepts/functions/edge-functions) or [Serverless Functions](https://vercel.com/docs/concepts/functions/serverless-functions) @@ -75,6 +92,12 @@ export interface EdgeConfig { * If `true`, this route will always be deployed as its own separate function */ split?: boolean; + + /** + * Advanced. Modify the bundling step's config + * @see https://esbuild.github.io/api/#build + */ + esbuild?: esbuild; } export type Config = EdgeConfig | ServerlessConfig; diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 0f02652f8e3d..2baa0ba82e64 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -114,7 +114,8 @@ const plugin = function (defaults = {}) { `export const manifest = ${builder.generateManifest({ relativePath, routes })};\n` ); - await esbuild.build({ + /** @type { import('.').DefaultEsbuildOptions } */ + const default_bundler_props = { entryPoints: [`${tmp}/edge.js`], outfile: `${dirs.functions}/${name}.func/index.js`, target: 'es2020', // TODO verify what the edge runtime supports @@ -124,7 +125,22 @@ const plugin = function (defaults = {}) { external: config.external, sourcemap: 'linked', banner: { js: 'globalThis.global = globalThis;' } - }); + }; + + if (defaults['esbuild'] && typeof defaults['esbuild'] !== 'function') { + throw new Error( + `Type of esbuild must be a function if defined. Type provided ${typeof defaults[ + 'esbuild' + ]}` + ); + } + + /** @type { import('.').DefaultEsbuildOptions } */ + const bundler_props = defaults['esbuild'] + ? defaults['esbuild'](default_bundler_props) + : default_bundler_props; + + await esbuild.build(bundler_props); write( `${dirs.functions}/${name}.func/.vc-config.json`,