@sveltejs/adapter-vercel 5.6.3 → 5.7.1

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.
Files changed (2) hide show
  1. package/index.js +64 -20
  2. package/package.json +4 -4
package/index.js CHANGED
@@ -8,7 +8,7 @@ import { get_pathname, pattern_to_src } from './utils.js';
8
8
  import { VERSION } from '@sveltejs/kit';
9
9
 
10
10
  const name = '@sveltejs/adapter-vercel';
11
- const DEFAULT_FUNCTION_NAME = 'fn';
11
+ const INTERNAL = '![-]'; // this name is guaranteed not to conflict with user routes
12
12
 
13
13
  const get_default_runtime = () => {
14
14
  const major = Number(process.version.slice(1).split('.')[0]);
@@ -137,9 +137,19 @@ const plugin = function (defaults = {}) {
137
137
  const result = await esbuild.build({
138
138
  entryPoints: [`${tmp}/edge.js`],
139
139
  outfile: `${dirs.functions}/${name}.func/index.js`,
140
- target: 'es2020', // TODO verify what the edge runtime supports
140
+ // minimum Node.js version supported is v14.6.0 that is mapped to ES2019
141
+ // https://edge-runtime.vercel.app/features/polyfills
142
+ // TODO verify the latest ES version the edge runtime supports
143
+ target: 'es2020',
141
144
  bundle: true,
142
145
  platform: 'browser',
146
+ conditions: [
147
+ // Vercel's Edge runtime key https://runtime-keys.proposal.wintercg.org/#edge-light
148
+ 'edge-light',
149
+ // re-include these since they are included by default when no conditions are specified
150
+ // https://esbuild.github.io/api/#conditions
151
+ 'module'
152
+ ],
143
153
  format: 'esm',
144
154
  external: [
145
155
  ...compatible_node_modules,
@@ -319,7 +329,7 @@ const plugin = function (defaults = {}) {
319
329
  group.config.runtime === 'edge' ? generate_edge_function : generate_serverless_function;
320
330
 
321
331
  // generate one function for the group
322
- const name = singular ? DEFAULT_FUNCTION_NAME : `fn-${group.i}`;
332
+ const name = singular ? `${INTERNAL}/catchall` : `${INTERNAL}/${group.i}`;
323
333
 
324
334
  await generate_function(
325
335
  name,
@@ -332,12 +342,27 @@ const plugin = function (defaults = {}) {
332
342
  }
333
343
  }
334
344
 
345
+ if (!singular) {
346
+ // we need to create a catch-all route so that 404s are handled
347
+ // by SvelteKit rather than Vercel
348
+
349
+ const runtime = defaults.runtime ?? get_default_runtime();
350
+ const generate_function =
351
+ runtime === 'edge' ? generate_edge_function : generate_serverless_function;
352
+
353
+ await generate_function(
354
+ `${INTERNAL}/catchall`,
355
+ /** @type {any} */ ({ runtime, ...defaults }),
356
+ []
357
+ );
358
+ }
359
+
335
360
  for (const route of builder.routes) {
336
361
  if (is_prerendered(route)) continue;
337
362
 
338
363
  const pattern = route.pattern.toString();
339
364
  const src = pattern_to_src(pattern);
340
- const name = functions.get(pattern) ?? 'fn-0';
365
+ const name = functions.get(pattern);
341
366
 
342
367
  const isr = isr_config.get(route);
343
368
  if (isr) {
@@ -370,24 +395,43 @@ const plugin = function (defaults = {}) {
370
395
  src: src + '/__data.json$',
371
396
  dest: `/${isr_name}/__data.json${q}`
372
397
  });
373
- } else if (!singular) {
374
- static_config.routes.push({ src: src + '(?:/__data.json)?$', dest: `/${name}` });
375
- }
376
- }
398
+ } else {
399
+ // Create a symlink for each route to the main function for better observability
400
+ // (without this, every request appears to go through `/![-]`)
377
401
 
378
- if (!singular) {
379
- // we need to create a catch-all route so that 404s are handled
380
- // by SvelteKit rather than Vercel
402
+ // Use 'index' for the root route's filesystem representation
403
+ // Use an empty string ('') for the root route's destination name part in Vercel config
404
+ const is_root = route.id === '/';
405
+ const route_fs_name = is_root ? 'index' : route.id.slice(1);
406
+ const route_dest_name = is_root ? '' : route.id.slice(1);
381
407
 
382
- const runtime = defaults.runtime ?? get_default_runtime();
383
- const generate_function =
384
- runtime === 'edge' ? generate_edge_function : generate_serverless_function;
408
+ // Define paths using path.join for safety
409
+ const base_dir = path.join(dirs.functions, route_fs_name); // e.g., .vercel/output/functions/index
410
+ // The main symlink should be named based on the route, adjacent to its potential directory
411
+ const main_symlink_path = `${base_dir}.func`; // e.g., .vercel/output/functions/index.func
412
+ // The data symlink goes inside the directory
413
+ const data_symlink_path = path.join(base_dir, '__data.json.func'); // e.g., .vercel/output/functions/index/__data.json.func
385
414
 
386
- await generate_function(
387
- DEFAULT_FUNCTION_NAME,
388
- /** @type {any} */ ({ runtime, ...defaults }),
389
- []
390
- );
415
+ const target = path.join(dirs.functions, `${name}.func`); // The actual function directory e.g., .vercel/output/functions/![-].func
416
+
417
+ // Ensure the directory for the data endpoint symlink exists (e.g., functions/index/)
418
+ builder.mkdirp(base_dir);
419
+
420
+ // Calculate relative paths FROM the directory containing the symlink TO the target
421
+ const relative_for_main = path.relative(path.dirname(main_symlink_path), target);
422
+ const relative_for_data = path.relative(path.dirname(data_symlink_path), target); // This is path.relative(base_dir, target)
423
+
424
+ // Create symlinks
425
+ fs.symlinkSync(relative_for_main, main_symlink_path); // Creates functions/index.func -> ![-].func
426
+ fs.symlinkSync(relative_for_data, data_symlink_path); // Creates functions/index/__data.json.func -> ../![-].func
427
+
428
+ // Add route to the config
429
+ static_config.routes.push({
430
+ src: src + '(?:/__data.json)?$', // Matches the incoming request path
431
+ dest: `/${route_dest_name}` // Maps to the function: '/' for root, '/about' for about, etc.
432
+ // Vercel uses this dest to find the corresponding .func dir/symlink
433
+ });
434
+ }
391
435
  }
392
436
 
393
437
  // optional chaining to support older versions that don't have this setting yet
@@ -412,7 +456,7 @@ const plugin = function (defaults = {}) {
412
456
 
413
457
  // Catch-all route must come at the end, otherwise it will swallow all other routes,
414
458
  // including ISR aliases if there is only one function
415
- static_config.routes.push({ src: '/.*', dest: `/${DEFAULT_FUNCTION_NAME}` });
459
+ static_config.routes.push({ src: '/.*', dest: `/${INTERNAL}/catchall` });
416
460
 
417
461
  builder.log.minor('Writing routes...');
418
462
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/adapter-vercel",
3
- "version": "5.6.3",
3
+ "version": "5.7.1",
4
4
  "description": "A SvelteKit adapter that creates a Vercel app",
5
5
  "keywords": [
6
6
  "adapter",
@@ -35,14 +35,14 @@
35
35
  ],
36
36
  "dependencies": {
37
37
  "@vercel/nft": "^0.29.2",
38
- "esbuild": "^0.24.0"
38
+ "esbuild": "^0.25.2"
39
39
  },
40
40
  "devDependencies": {
41
41
  "@sveltejs/vite-plugin-svelte": "^5.0.1",
42
42
  "@types/node": "^18.19.48",
43
43
  "typescript": "^5.3.3",
44
- "vitest": "^3.0.1",
45
- "@sveltejs/kit": "^2.17.2"
44
+ "vitest": "^3.1.1",
45
+ "@sveltejs/kit": "^2.20.8"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@sveltejs/kit": "^2.4.0"