@sveltejs/adapter-netlify 6.0.3 → 7.0.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/files/edge.js CHANGED
@@ -1,39 +1,28 @@
1
- import { Server } from '0SERVER';
2
- import { manifest } from 'MANIFEST';
3
-
1
+ import { Server } from "0SERVER";
2
+ import { manifest } from "MANIFEST";
3
+ //#region src/edge.js
4
4
  const server = new Server(manifest);
5
-
6
5
  /**
7
- * We don't know the origin until we receive a request, but
8
- * that's guaranteed to happen before we call `read`
9
- * @type {string}
10
- */
6
+ * We don't know the origin until we receive a request, but
7
+ * that's guaranteed to happen before we call `read`
8
+ * @type {string}
9
+ */
11
10
  let origin;
12
-
13
11
  const initialized = server.init({
14
- // @ts-ignore
15
12
  env: Deno.env.toObject(),
16
13
  read: async (file) => {
17
14
  const url = `${origin}/${file}`;
18
15
  const response = await fetch(url);
19
-
20
- if (!response.ok) {
21
- throw new Error(
22
- `read(...) failed: could not fetch ${url} (${response.status} ${response.statusText})`
23
- );
24
- }
25
-
16
+ if (!response.ok) throw new Error(`read(...) failed: could not fetch ${url} (${response.status} ${response.statusText})`);
26
17
  return response.body;
27
18
  }
28
19
  });
29
-
30
20
  /** @type {import('@netlify/edge-functions').EdgeFunction} */
31
21
  async function handler(request, context) {
32
22
  if (!origin) {
33
23
  origin = new URL(request.url).origin;
34
24
  await initialized;
35
25
  }
36
-
37
26
  return server.respond(request, {
38
27
  platform: { context },
39
28
  getClientAddress() {
@@ -41,5 +30,5 @@ async function handler(request, context) {
41
30
  }
42
31
  });
43
32
  }
44
-
33
+ //#endregion
45
34
  export { handler as default };
@@ -1,40 +1,35 @@
1
- import './shims.js';
2
- import { Server } from '0SERVER';
3
- import { createReadStream } from 'node:fs';
4
- import { Readable } from 'node:stream';
5
- import process from 'node:process';
6
- import 'node:buffer';
7
- import 'node:crypto';
8
-
1
+ import { Server } from "0SERVER";
2
+ import { createReadStream } from "node:fs";
3
+ import { Readable } from "node:stream";
4
+ import process from "node:process";
5
+ //#region ../kit/src/exports/node/index.js
9
6
  /**
10
- * Converts a file on disk to a readable stream
11
- * @param {string} file
12
- * @returns {ReadableStream}
13
- * @since 2.4.0
14
- */
7
+ * Converts a file on disk to a readable stream
8
+ * @param {string} file
9
+ * @returns {ReadableStream}
10
+ * @since 2.4.0
11
+ */
15
12
  function createReadableStream(file) {
16
- return /** @type {ReadableStream} */ (Readable.toWeb(createReadStream(file)));
13
+ return Readable.toWeb(createReadStream(file));
17
14
  }
18
-
15
+ //#endregion
16
+ //#region src/serverless.js
19
17
  /**
20
- * @param {import('@sveltejs/kit').SSRManifest} manifest
21
- * @returns {(request: Request, context: import('@netlify/functions').Context) => Promise<Response>}
22
- */
18
+ * @param {import('@sveltejs/kit').SSRManifest} manifest
19
+ * @returns {(request: Request, context: import('@netlify/functions').Context) => Promise<Response>}
20
+ */
23
21
  function init(manifest) {
24
22
  const server = new Server(manifest);
25
-
26
23
  /** @type {Promise<void> | null} */
27
24
  let init_promise = server.init({
28
- env: /** @type {Record<string, string>} */ (process.env),
25
+ env: process.env,
29
26
  read: (file) => createReadableStream(`.netlify/server/${file}`)
30
27
  });
31
-
32
28
  return async (request, context) => {
33
29
  if (init_promise !== null) {
34
30
  await init_promise;
35
31
  init_promise = null;
36
32
  }
37
-
38
33
  return server.respond(request, {
39
34
  platform: { context },
40
35
  getClientAddress() {
@@ -43,5 +38,5 @@ function init(manifest) {
43
38
  });
44
39
  };
45
40
  }
46
-
41
+ //#endregion
47
42
  export { init };
package/index.js CHANGED
@@ -1,11 +1,11 @@
1
- /** @import { BuildOptions } from 'esbuild' */
2
- import { appendFileSync, existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
3
- import { join, resolve, posix } from 'node:path';
1
+ import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join, posix } from 'node:path';
4
3
  import { fileURLToPath } from 'node:url';
5
4
  import { builtinModules } from 'node:module';
6
5
  import process from 'node:process';
7
- import esbuild from 'esbuild';
8
6
  import toml from '@iarna/toml';
7
+ import { build } from 'rolldown';
8
+ import { matches, get_publish_directory, s } from './utils.js';
9
9
 
10
10
  /**
11
11
  * @typedef {{
@@ -14,6 +14,9 @@ import toml from '@iarna/toml';
14
14
  * } & toml.JsonMap} NetlifyConfig
15
15
  */
16
16
 
17
+ const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf-8'));
18
+ const adapter_version = pkg.version;
19
+
17
20
  const name = '@sveltejs/adapter-netlify';
18
21
  const files = fileURLToPath(new URL('./files', import.meta.url).href);
19
22
 
@@ -21,13 +24,16 @@ const edge_set_in_env_var =
21
24
  process.env.NETLIFY_SVELTEKIT_USE_EDGE === 'true' ||
22
25
  process.env.NETLIFY_SVELTEKIT_USE_EDGE === '1';
23
26
 
27
+ const netlify_framework_config_path = '.netlify/v1/config.json';
28
+ const netlify_framework_serverless_path = '.netlify/v1/functions';
29
+ const netlify_framework_edge_path = '.netlify/v1/edge-functions';
30
+
24
31
  const FUNCTION_PREFIX = 'sveltekit-';
25
32
 
26
33
  /** @type {import('./index.js').default} */
27
34
  export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
28
35
  return {
29
36
  name,
30
- /** @param {import('@sveltejs/kit').Builder} builder */
31
37
  async adapt(builder) {
32
38
  if (!builder.routes) {
33
39
  throw new Error(
@@ -55,11 +61,14 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
55
61
 
56
62
  // empty out existing build directories
57
63
  builder.rimraf(publish);
64
+ builder.rimraf('.netlify/v1');
65
+
66
+ // clean up legacy directories from older adapter versions to avoid
67
+ // gnarly edge cases when an existing project is upgraded to this version
58
68
  builder.rimraf('.netlify/edge-functions');
59
69
  builder.rimraf('.netlify/server');
60
70
  builder.rimraf('.netlify/package.json');
61
71
  builder.rimraf('.netlify/serverless.js');
62
-
63
72
  if (existsSync('.netlify/functions-internal')) {
64
73
  for (const file of readdirSync('.netlify/functions-internal')) {
65
74
  if (file.startsWith(FUNCTION_PREFIX)) {
@@ -75,13 +84,13 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
75
84
  builder.writeClient(publish_dir);
76
85
  builder.writePrerendered(publish_dir);
77
86
 
78
- builder.log.minor('Writing custom headers...');
79
- const headers_file = join(publish, '_headers');
80
- builder.copy('_headers', headers_file);
81
- appendFileSync(
82
- headers_file,
83
- `\n\n/${builder.getAppPath()}/immutable/*\n cache-control: public\n cache-control: immutable\n cache-control: max-age=31536000\n`
84
- );
87
+ // Copy user's custom _headers file if it exists
88
+ if (existsSync('_headers')) {
89
+ builder.copy('_headers', join(publish, '_headers'));
90
+ }
91
+
92
+ builder.log.minor('Writing Netlify config...');
93
+ write_frameworks_config({ builder });
85
94
 
86
95
  if (edge) {
87
96
  if (split) {
@@ -90,7 +99,7 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
90
99
 
91
100
  await generate_edge_functions({ builder });
92
101
  } else {
93
- generate_lambda_functions({ builder, split, publish });
102
+ generate_serverless_functions({ builder, split, publish });
94
103
  }
95
104
  },
96
105
 
@@ -100,131 +109,24 @@ export default function ({ split = false, edge = edge_set_in_env_var } = {}) {
100
109
  }
101
110
  };
102
111
  }
103
- /**
104
- * @param { object } params
105
- * @param {import('@sveltejs/kit').Builder} params.builder
106
- */
107
- async function generate_edge_functions({ builder }) {
108
- const tmp = builder.getBuildDirectory('netlify-tmp');
109
- builder.rimraf(tmp);
110
- builder.mkdirp(tmp);
111
-
112
- builder.mkdirp('.netlify/edge-functions');
113
-
114
- builder.log.minor('Generating Edge Function...');
115
- const relativePath = posix.relative(tmp, builder.getServerDirectory());
116
-
117
- builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, {
118
- replace: {
119
- '0SERVER': `${relativePath}/index.js`,
120
- MANIFEST: './manifest.js'
121
- }
122
- });
123
-
124
- const manifest = builder.generateManifest({
125
- relativePath
126
- });
127
-
128
- writeFileSync(`${tmp}/manifest.js`, `export const manifest = ${manifest};\n`);
129
-
130
- /** @type {{ assets: Set<string> }} */
131
- // we have to prepend the file:// protocol because Windows doesn't support absolute path imports
132
- const { assets } = (await import(`file://${tmp}/manifest.js`)).manifest;
133
-
134
- const path = '/*';
135
- // We only need to specify paths without the trailing slash because
136
- // Netlify will handle the optional trailing slash for us
137
- const excluded = [
138
- // Contains static files
139
- `/${builder.getAppPath()}/immutable/*`,
140
- `/${builder.getAppPath()}/version.json`,
141
- ...builder.prerendered.paths,
142
- ...Array.from(assets).flatMap((asset) => {
143
- if (asset.endsWith('/index.html')) {
144
- const dir = asset.replace(/\/index\.html$/, '');
145
- return [
146
- `${builder.config.kit.paths.base}/${asset}`,
147
- `${builder.config.kit.paths.base}/${dir}`
148
- ];
149
- }
150
- return `${builder.config.kit.paths.base}/${asset}`;
151
- }),
152
- // Should not be served by SvelteKit at all
153
- '/.netlify/*'
154
- ];
155
-
156
- /** @type {import('@netlify/edge-functions').Manifest} */
157
- const edge_manifest = {
158
- functions: [
159
- {
160
- function: 'render',
161
- path,
162
- excludedPath: /** @type {`/${string}`[]} */ (excluded)
163
- }
164
- ],
165
- version: 1
166
- };
167
-
168
- /** @type {BuildOptions} */
169
- const esbuild_config = {
170
- bundle: true,
171
- format: 'esm',
172
- platform: 'browser',
173
- sourcemap: 'linked',
174
- target: 'es2020',
175
- loader: {
176
- '.wasm': 'copy',
177
- '.woff': 'copy',
178
- '.woff2': 'copy',
179
- '.ttf': 'copy',
180
- '.eot': 'copy',
181
- '.otf': 'copy'
182
- },
183
- // Node built-ins are allowed, but must be prefixed with `node:`
184
- // https://docs.netlify.com/edge-functions/api/#runtime-environment
185
- external: builtinModules.map((id) => `node:${id}`),
186
- alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`]))
187
- };
188
- await Promise.all([
189
- esbuild.build({
190
- entryPoints: [`${tmp}/entry.js`],
191
- outfile: '.netlify/edge-functions/render.js',
192
- ...esbuild_config
193
- }),
194
- builder.hasServerInstrumentationFile() &&
195
- esbuild.build({
196
- entryPoints: [`${builder.getServerDirectory()}/instrumentation.server.js`],
197
- outfile: '.netlify/edge/instrumentation.server.js',
198
- ...esbuild_config
199
- })
200
- ]);
201
112
 
202
- if (builder.hasServerInstrumentationFile()) {
203
- builder.instrument({
204
- entrypoint: '.netlify/edge-functions/render.js',
205
- instrumentation: '.netlify/edge/instrumentation.server.js',
206
- start: '.netlify/edge/start.js'
207
- });
208
- }
209
-
210
- writeFileSync('.netlify/edge-functions/manifest.json', JSON.stringify(edge_manifest));
211
- }
212
113
  /**
213
114
  * @param { object } params
214
115
  * @param {import('@sveltejs/kit').Builder} params.builder
215
116
  * @param { string } params.publish
216
117
  * @param { boolean } params.split
217
118
  */
218
- function generate_lambda_functions({ builder, publish, split }) {
219
- builder.mkdirp('.netlify/functions-internal/.svelte-kit');
119
+ function generate_serverless_functions({ builder, publish, split }) {
120
+ // https://docs.netlify.com/build/frameworks/frameworks-api/#netlifyv1functions
121
+ builder.mkdirp(netlify_framework_serverless_path);
220
122
 
221
- builder.writeServer('.netlify/server');
123
+ builder.writeServer('.netlify/v1/server');
222
124
 
223
125
  const replace = {
224
126
  '0SERVER': './server/index.js' // digit prefix prevents CJS build from using this as a variable name, which would also get replaced
225
127
  };
226
128
 
227
- builder.copy(files, '.netlify', { replace, filter: (name) => !name.endsWith('edge.js') });
129
+ builder.copy(files, '.netlify/v1', { replace, filter: (file) => !file.endsWith('edge.js') });
228
130
 
229
131
  builder.log.minor('Generating serverless functions...');
230
132
 
@@ -260,7 +162,9 @@ function generate_lambda_functions({ builder, publish, split }) {
260
162
 
261
163
  // skip routes with identical patterns, they were already folded into another function
262
164
  if (seen.has(pattern)) continue;
263
- seen.add(pattern);
165
+
166
+ const patterns = [pattern, `${pattern === '/' ? '' : pattern}/__data.json`];
167
+ patterns.forEach((p) => seen.add(p));
264
168
 
265
169
  // figure out which lower priority routes should be considered fallbacks
266
170
  for (let j = i + 1; j < builder.routes.length; j += 1) {
@@ -275,12 +179,18 @@ function generate_lambda_functions({ builder, publish, split }) {
275
179
  generate_serverless_function({
276
180
  builder,
277
181
  routes,
278
- patterns: [pattern, `${pattern === '/' ? '' : pattern}/__data.json`],
182
+ patterns,
279
183
  name
280
184
  });
281
185
  }
282
186
 
283
- // TODO: add a catch-all to display a 404 page if no other functions are invoked, similar to the Vercel adapter
187
+ generate_serverless_function({
188
+ builder,
189
+ routes: [],
190
+ patterns: ['/*'],
191
+ name: `${FUNCTION_PREFIX}catch-all`,
192
+ exclude: Array.from(seen)
193
+ });
284
194
  } else {
285
195
  generate_serverless_function({
286
196
  builder,
@@ -298,75 +208,43 @@ function generate_lambda_functions({ builder, publish, split }) {
298
208
  }
299
209
  }
300
210
 
211
+ /**
212
+ * @returns {NetlifyConfig | null}
213
+ */
301
214
  function get_netlify_config() {
302
215
  if (!existsSync('netlify.toml')) return null;
303
216
 
304
217
  try {
305
- return /** @type {NetlifyConfig} */ (toml.parse(readFileSync('netlify.toml', 'utf-8')));
218
+ return toml.parse(readFileSync('netlify.toml', 'utf-8'));
306
219
  } catch (err) {
307
- err.message = `Error parsing netlify.toml: ${err.message}`;
308
- throw err;
309
- }
310
- }
311
-
312
- /**
313
- * @param {NetlifyConfig | null} netlify_config
314
- * @param {import('@sveltejs/kit').Builder} builder
315
- **/
316
- function get_publish_directory(netlify_config, builder) {
317
- if (netlify_config) {
318
- if (!netlify_config.build?.publish) {
319
- builder.log.minor('No publish directory specified in netlify.toml, using default');
320
- return;
220
+ if (err instanceof Error) {
221
+ throw new Error(`Failed to parse netlify.toml: ${err.message}`, { cause: err });
321
222
  }
322
-
323
- if (resolve(netlify_config.build.publish) === process.cwd()) {
324
- throw new Error(
325
- 'The publish directory cannot be set to the site root. Please change it to another value such as "build" in netlify.toml.'
326
- );
327
- }
328
- return netlify_config.build.publish;
223
+ throw err;
329
224
  }
330
-
331
- builder.log.warn(
332
- 'No netlify.toml found. Using default publish directory. Consult https://svelte.dev/docs/kit/adapter-netlify#usage for more details'
333
- );
334
225
  }
335
226
 
336
227
  /**
337
- * @typedef {{ rest: boolean, dynamic: boolean, content: string }} RouteSegment
338
- */
339
-
340
- /**
341
- * @param {RouteSegment[]} a
342
- * @param {RouteSegment[]} b
343
- * @returns {boolean}
228
+ * Writes the Netlify Frameworks API config file
229
+ * https://docs.netlify.com/build/frameworks/frameworks-api/
230
+ * @param {{ builder: import('@sveltejs/kit').Builder }} params
344
231
  */
345
- function matches(a, b) {
346
- if (a[0] && b[0]) {
347
- if (b[0].rest) {
348
- if (b.length === 1) return true;
349
-
350
- const next_b = b.slice(1);
351
-
352
- for (let i = 0; i < a.length; i += 1) {
353
- if (matches(a.slice(i), next_b)) return true;
232
+ function write_frameworks_config({ builder }) {
233
+ // https://docs.netlify.com/build/frameworks/frameworks-api/#headers
234
+ /** @type {{ headers: Array<{ for: string, values: Record<string, string> }> }} */
235
+ const config = {
236
+ headers: [
237
+ {
238
+ for: `/${builder.getAppPath()}/immutable/*`,
239
+ values: {
240
+ 'cache-control': 'public, immutable, max-age=31536000'
241
+ }
354
242
  }
243
+ ]
244
+ };
355
245
 
356
- return false;
357
- }
358
-
359
- if (!b[0].dynamic) {
360
- if (!a[0].dynamic && a[0].content !== b[0].content) return false;
361
- }
362
-
363
- if (a.length === 1 && b.length === 1) return true;
364
- return matches(a.slice(1), b.slice(1));
365
- } else if (a[0]) {
366
- return a.length === 1 && a[0].rest;
367
- } else {
368
- return b.length === 1 && b[0].rest;
369
- }
246
+ builder.mkdirp('.netlify/v1');
247
+ writeFileSync(netlify_framework_config_path, s(config));
370
248
  }
371
249
 
372
250
  /**
@@ -375,30 +253,31 @@ function matches(a, b) {
375
253
  * builder: import('@sveltejs/kit').Builder,
376
254
  * routes: import('@sveltejs/kit').RouteDefinition[] | undefined,
377
255
  * patterns: string[],
378
- * name: string
256
+ * name: string,
257
+ * exclude?: string[]
379
258
  * }} opts
380
259
  */
381
- function generate_serverless_function({ builder, routes, patterns, name }) {
260
+ function generate_serverless_function({ builder, routes, patterns, name, exclude }) {
382
261
  const manifest = builder.generateManifest({
383
262
  relativePath: '../server',
384
263
  routes
385
264
  });
386
265
 
387
266
  const fn = generate_serverless_function_module(manifest);
388
- const config = generate_config_export(patterns);
267
+ const config = generate_config_export(patterns, exclude);
389
268
 
390
269
  if (builder.hasServerInstrumentationFile()) {
391
- writeFileSync(`.netlify/functions-internal/${name}.mjs`, fn);
270
+ writeFileSync(`${netlify_framework_serverless_path}/${name}.mjs`, fn);
392
271
  builder.instrument({
393
- entrypoint: `.netlify/functions-internal/${name}.mjs`,
394
- instrumentation: '.netlify/server/instrumentation.server.js',
395
- start: `.netlify/functions-start/${name}.start.mjs`,
272
+ entrypoint: `${netlify_framework_serverless_path}/${name}.mjs`,
273
+ instrumentation: '.netlify/v1/server/instrumentation.server.js',
274
+ start: `.netlify/v1/server/${name}.start.mjs`,
396
275
  module: {
397
276
  generateText: generate_traced_module(config)
398
277
  }
399
278
  });
400
279
  } else {
401
- writeFileSync(`.netlify/functions-internal/${name}.mjs`, `${fn}\n${config}`);
280
+ writeFileSync(`${netlify_framework_serverless_path}/${name}.mjs`, `${fn}\n${config}`);
402
281
  }
403
282
  }
404
283
 
@@ -414,16 +293,23 @@ export default init(${manifest});
414
293
  `;
415
294
  }
416
295
 
296
+ const generator_string = `@sveltejs/adapter-netlify@${adapter_version}`;
297
+
417
298
  /**
418
299
  * @param {string[]} patterns
300
+ * @param {string[]} [exclude]
419
301
  * @returns {string}
420
302
  */
421
- function generate_config_export(patterns) {
303
+ function generate_config_export(patterns, exclude = []) {
422
304
  // TODO: add a human friendly name for the function https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-2
305
+
306
+ // https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-2
423
307
  return `\
424
308
  export const config = {
425
- path: [${patterns.map((s) => JSON.stringify(s)).join(', ')}],
426
- excludedPath: "/.netlify/*",
309
+ name: 'SvelteKit server',
310
+ generator: '${generator_string}',
311
+ path: [${patterns.map(s).join(', ')}],
312
+ excludedPath: [${['/.netlify/*', ...exclude].map(s).join(', ')}],
427
313
  preferStatic: true
428
314
  };
429
315
  `;
@@ -436,10 +322,135 @@ export const config = {
436
322
  function generate_traced_module(config) {
437
323
  return ({ instrumentation, start }) => {
438
324
  return `\
439
- import './${instrumentation}';
440
- const { default: _0 } = await import('./${start}');
325
+ import '../server/${instrumentation}';
326
+ const { default: _0 } = await import('../server/${start}');
441
327
  export { _0 as default };
442
328
 
443
329
  ${config}`;
444
330
  };
445
331
  }
332
+
333
+ /** @satisfies {import('rolldown').BuildOptions} */
334
+ const rolldown_config = {
335
+ platform: 'browser',
336
+ output: {
337
+ sourcemap: true,
338
+ codeSplitting: false
339
+ },
340
+ transform: {
341
+ target: 'es2022'
342
+ },
343
+ // Node built-ins are allowed, but must be prefixed with `node:`
344
+ // https://docs.netlify.com/edge-functions/api/#runtime-environment
345
+ external: builtinModules.map((id) => `node:${id}`),
346
+ resolve: {
347
+ alias: Object.fromEntries(builtinModules.map((id) => [id, `node:${id}`]))
348
+ }
349
+ };
350
+
351
+ /**
352
+ * @param { object } params
353
+ * @param {import('@sveltejs/kit').Builder} params.builder
354
+ */
355
+ async function generate_edge_functions({ builder }) {
356
+ const tmp = builder.getBuildDirectory('netlify-tmp');
357
+ builder.rimraf(tmp);
358
+ builder.mkdirp(tmp);
359
+
360
+ // https://docs.netlify.com/build/frameworks/frameworks-api/#edge-functions
361
+ builder.mkdirp('.netlify/v1/edge-functions');
362
+
363
+ builder.log.minor('Generating Edge Function...');
364
+ const relativePath = posix.relative(tmp, builder.getServerDirectory());
365
+
366
+ builder.copy(`${files}/edge.js`, `${tmp}/entry.js`, {
367
+ replace: {
368
+ '0SERVER': `${relativePath}/index.js`,
369
+ MANIFEST: './manifest.js'
370
+ }
371
+ });
372
+
373
+ const manifest = builder.generateManifest({
374
+ relativePath
375
+ });
376
+
377
+ writeFileSync(`${tmp}/manifest.js`, `export const manifest = ${manifest};\n`);
378
+
379
+ /** @type {{ assets: Set<string> }} */
380
+ // we have to prepend the file:// protocol because Windows doesn't support absolute path imports
381
+ const { assets } = (await import(`file://${tmp}/manifest.js`)).manifest;
382
+
383
+ const path = '/*';
384
+ // We only need to specify paths without the trailing slash because
385
+ // Netlify will handle the optional trailing slash for us
386
+ const excluded_paths = [
387
+ // Contains static files
388
+ `/${builder.getAppPath()}/immutable/*`,
389
+ `/${builder.getAppPath()}/version.json`,
390
+ ...builder.prerendered.paths,
391
+ ...Array.from(assets).flatMap((asset) => {
392
+ if (asset.endsWith('/index.html')) {
393
+ const dir = asset.replace(/\/index\.html$/, '');
394
+ return [
395
+ `${builder.config.kit.paths.base}/${asset}`,
396
+ `${builder.config.kit.paths.base}/${dir}`
397
+ ];
398
+ }
399
+ return `${builder.config.kit.paths.base}/${asset}`;
400
+ }),
401
+ // Should not be served by SvelteKit at all
402
+ '/.netlify/*'
403
+ ];
404
+
405
+ await Promise.all([
406
+ build({
407
+ ...rolldown_config,
408
+ input: `${tmp}/entry.js`,
409
+ output: {
410
+ ...rolldown_config.output,
411
+ file: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}render.js`
412
+ }
413
+ }),
414
+ builder.hasServerInstrumentationFile() &&
415
+ build({
416
+ ...rolldown_config,
417
+ input: `${builder.getServerDirectory()}/instrumentation.server.js`,
418
+ output: {
419
+ ...rolldown_config.output,
420
+ file: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}instrumentation.server.js`
421
+ }
422
+ })
423
+ ]);
424
+
425
+ if (builder.hasServerInstrumentationFile()) {
426
+ builder.instrument({
427
+ entrypoint: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}render.js`,
428
+ instrumentation: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}instrumentation.server.js`,
429
+ start: `${netlify_framework_edge_path}/${FUNCTION_PREFIX}start.js`
430
+ });
431
+ }
432
+
433
+ add_edge_function_config({ builder, path, excluded_paths });
434
+ }
435
+
436
+ /**
437
+ * Adds edge function configuration to the Frameworks API config file `config.json`
438
+ * https://docs.netlify.com/build/frameworks/frameworks-api/#netlifyv1edge-functions
439
+ * @param {{ builder: import('@sveltejs/kit').Builder, path: string, excluded_paths: string[] }} params
440
+ */
441
+ function add_edge_function_config({ path, excluded_paths }) {
442
+ const config = JSON.parse(readFileSync(netlify_framework_config_path, 'utf-8'));
443
+
444
+ // https://docs.netlify.com/build/frameworks/frameworks-api/#configuration-options-1
445
+ config.edge_functions = [
446
+ {
447
+ function: `${FUNCTION_PREFIX}render`,
448
+ name: 'SvelteKit server',
449
+ generator: generator_string,
450
+ path,
451
+ excludedPath: excluded_paths
452
+ }
453
+ ];
454
+
455
+ writeFileSync(netlify_framework_config_path, s(config));
456
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/adapter-netlify",
3
- "version": "6.0.3",
3
+ "version": "7.0.0-next.0",
4
4
  "description": "A SvelteKit adapter that creates a Netlify app",
5
5
  "keywords": [
6
6
  "adapter",
@@ -34,7 +34,7 @@
34
34
  ],
35
35
  "dependencies": {
36
36
  "@iarna/toml": "^2.2.5",
37
- "esbuild": "^0.25.4"
37
+ "rolldown": "^1.0.0-rc.6"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@netlify/dev": "^4.11.2",
@@ -42,26 +42,21 @@
42
42
  "@netlify/functions": "^5.0.0",
43
43
  "@netlify/node-cookies": "^0.1.0",
44
44
  "@netlify/types": "^2.1.0",
45
- "@rollup/plugin-commonjs": "^29.0.0",
46
- "@rollup/plugin-json": "^6.1.0",
47
- "@rollup/plugin-node-resolve": "^16.0.0",
48
- "@sveltejs/vite-plugin-svelte": "^6.0.0-next.3",
49
- "@types/node": "^18.19.119",
50
- "rollup": "^4.14.2",
51
- "typescript": "^5.3.3",
52
- "vitest": "^4.0.0",
53
- "@sveltejs/kit": "^2.53.0"
45
+ "@types/node": "^22.19.19",
46
+ "typescript": "^6.0.3",
47
+ "vitest": "^4.1.7",
48
+ "@sveltejs/kit": "^3.0.0-next.0"
54
49
  },
55
50
  "peerDependencies": {
56
51
  "@sveltejs/kit": "^2.31.0"
57
52
  },
58
53
  "scripts": {
59
- "dev": "rollup -cw",
60
- "build": "rollup -c",
54
+ "dev": "rolldown -cw",
55
+ "build": "rolldown -c",
61
56
  "check": "tsc",
62
57
  "lint": "prettier --check .",
63
58
  "format": "pnpm lint --write",
64
- "test": "pnpm test:integration",
59
+ "test": "pnpm test:unit && pnpm test:integration",
65
60
  "test:unit": "vitest run",
66
61
  "test:integration": "pnpm build && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test"
67
62
  }
package/files/shims.js DELETED
@@ -1,32 +0,0 @@
1
- import buffer from 'node:buffer';
2
- import { webcrypto } from 'node:crypto';
3
-
4
- // `buffer.File` was added in Node 18.13.0 while the `File` global was added in Node 20.0.0
5
- const File = /** @type {import('node:buffer') & { File?: File}} */ (buffer).File;
6
-
7
- /** @type {Record<string, any>} */
8
- const globals = {
9
- crypto: webcrypto,
10
- File
11
- };
12
-
13
- // exported for dev/preview and node environments
14
- /**
15
- * Make various web APIs available as globals:
16
- * - `crypto`
17
- * - `File`
18
- */
19
- function installPolyfills() {
20
- for (const name in globals) {
21
- if (name in globalThis) continue;
22
-
23
- Object.defineProperty(globalThis, name, {
24
- enumerable: true,
25
- configurable: true,
26
- writable: true,
27
- value: globals[name]
28
- });
29
- }
30
- }
31
-
32
- installPolyfills();