From 61a5a97f94dc6d9090af5e7147355d5d358091b7 Mon Sep 17 00:00:00 2001 From: Tobias Lins Date: Thu, 3 Apr 2025 16:31:08 +0200 Subject: [PATCH 1/5] Implement better build output using symlinks --- packages/adapter-vercel/index.js | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index d87f6946ed79..cfba13e2ce21 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -372,6 +372,47 @@ const plugin = function (defaults = {}) { }); } else if (!singular) { static_config.routes.push({ src: src + '(?:/__data.json)?$', dest: `/${name}` }); + } else { + // Create a symlink for each route to the main function + + // Use 'index' for the root route's filesystem representation + // Use an empty string ('') for the root route's destination name part in Vercel config + const isRoot = route.id === '/'; + const route_fs_name = isRoot ? 'index' : route.id.slice(1); + const route_dest_name = isRoot ? '' : route.id.slice(1); + + // Define paths using path.join for safety + const base_dir = path.join(dirs.functions, route_fs_name); // e.g., .vercel/output/functions/index + // The main symlink should be named based on the route, adjacent to its potential directory + const main_symlink_path = `${base_dir}.func`; // e.g., .vercel/output/functions/index.func + // The data symlink goes inside the directory + const data_symlink_path = path.join(base_dir, '__data.json.func'); // e.g., .vercel/output/functions/index/__data.json.func + + const target = path.join(dirs.functions, `${name}.func`); // The actual function directory e.g., .vercel/output/functions/fn.func + + // Ensure the directory for the data endpoint symlink exists (e.g., functions/index/) + builder.mkdirp(base_dir); + + // Calculate relative paths FROM the directory containing the symlink TO the target + const relative_for_main = path.relative( + path.dirname(main_symlink_path), + target, + ); + const relative_for_data = path.relative( + path.dirname(data_symlink_path), + target, + ); // This is path.relative(base_dir, target) + + // Create symlinks + fs.symlinkSync(relative_for_main, main_symlink_path); // Creates functions/index.func -> fn.func + fs.symlinkSync(relative_for_data, data_symlink_path); // Creates functions/index/__data.json.func -> ../fn.func + + // Add route to the config + static_config.routes.push({ + src: src + '(?:/__data.json)?$', // Matches the incoming request path + dest: `/${route_dest_name}`, // Maps to the function: '/' for root, '/about' for about, etc. + // Vercel uses this dest to find the corresponding .func dir/symlink + }); } } From 3d2f4e2d739d3a28cf2a6706659008a659a1ee9b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 4 Apr 2025 09:37:31 -0400 Subject: [PATCH 2/5] snake_case --- packages/adapter-vercel/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index cfba13e2ce21..fae961be96ef 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -377,9 +377,9 @@ const plugin = function (defaults = {}) { // Use 'index' for the root route's filesystem representation // Use an empty string ('') for the root route's destination name part in Vercel config - const isRoot = route.id === '/'; - const route_fs_name = isRoot ? 'index' : route.id.slice(1); - const route_dest_name = isRoot ? '' : route.id.slice(1); + const is_root = route.id === '/'; + const route_fs_name = is_root ? 'index' : route.id.slice(1); + const route_dest_name = is_root ? '' : route.id.slice(1); // Define paths using path.join for safety const base_dir = path.join(dirs.functions, route_fs_name); // e.g., .vercel/output/functions/index From 134a00628aa0b03f7797bb53aca882225b6b06d0 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 4 Apr 2025 09:37:38 -0400 Subject: [PATCH 3/5] prettier --- packages/adapter-vercel/index.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index fae961be96ef..b63be093d025 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -394,14 +394,8 @@ const plugin = function (defaults = {}) { builder.mkdirp(base_dir); // Calculate relative paths FROM the directory containing the symlink TO the target - const relative_for_main = path.relative( - path.dirname(main_symlink_path), - target, - ); - const relative_for_data = path.relative( - path.dirname(data_symlink_path), - target, - ); // This is path.relative(base_dir, target) + const relative_for_main = path.relative(path.dirname(main_symlink_path), target); + const relative_for_data = path.relative(path.dirname(data_symlink_path), target); // This is path.relative(base_dir, target) // Create symlinks fs.symlinkSync(relative_for_main, main_symlink_path); // Creates functions/index.func -> fn.func @@ -410,7 +404,7 @@ const plugin = function (defaults = {}) { // Add route to the config static_config.routes.push({ src: src + '(?:/__data.json)?$', // Matches the incoming request path - dest: `/${route_dest_name}`, // Maps to the function: '/' for root, '/about' for about, etc. + dest: `/${route_dest_name}` // Maps to the function: '/' for root, '/about' for about, etc. // Vercel uses this dest to find the corresponding .func dir/symlink }); } From 75e2170be22608d76daf477276c7f86ad3a556b1 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 4 Apr 2025 09:38:16 -0400 Subject: [PATCH 4/5] explanatory comment --- packages/adapter-vercel/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index b63be093d025..390f44c7aae4 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -373,7 +373,8 @@ const plugin = function (defaults = {}) { } else if (!singular) { static_config.routes.push({ src: src + '(?:/__data.json)?$', dest: `/${name}` }); } else { - // Create a symlink for each route to the main function + // Create a symlink for each route to the main function for better observability + // (without this, every request appears to go through `/fn` or `fn-{n}`) // Use 'index' for the root route's filesystem representation // Use an empty string ('') for the root route's destination name part in Vercel config From 122c67704de74019b325142fce0e9b0c089d9788 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 4 Apr 2025 10:21:00 -0400 Subject: [PATCH 5/5] generate symlinks when app uses function splitting --- packages/adapter-vercel/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/adapter-vercel/index.js b/packages/adapter-vercel/index.js index 390f44c7aae4..2a22d67821fc 100644 --- a/packages/adapter-vercel/index.js +++ b/packages/adapter-vercel/index.js @@ -370,8 +370,6 @@ const plugin = function (defaults = {}) { src: src + '/__data.json$', dest: `/${isr_name}/__data.json${q}` }); - } else if (!singular) { - static_config.routes.push({ src: src + '(?:/__data.json)?$', dest: `/${name}` }); } else { // Create a symlink for each route to the main function for better observability // (without this, every request appears to go through `/fn` or `fn-{n}`)