Open LorisSigrist opened 6 months ago
What would probably be required here is to run the reroute
hook in a Vercel Middleware function.
This isn't hard, per-se, but it would likely require bundling hook.js
separately & extending the adapter API in order to get access to it.
Not sure if it might be related or not but I encounter another issue that happens in the exact same conditions. Sadly I've been unable to find the time to create and deploy on Vercel a reproduction. Sorry if this is useless noise 🙏
In a form action, I trigger an internal fetch
call to a +server.ts
route handler.
This route handler returns json data (return json({ ... })
).
The route handler crashes with TypeError: immutable
(full error below), and the action receives { message: 'Internal Error' }
. Despite what the error message implies, I'm not trying to either set cookies or headers anywhere.
split: true
)TypeError: immutable
at _Headers.append (node:internal/deps/undici/undici:2105:17)
at add_cookies_to_headers (file:///var/task/vercel/path0/apps/client/.svelte-kit/output/server/index.js:2320:13)
at file:///var/task/vercel/path0/apps/client/.svelte-kit/output/server/index.js:2649:9
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
at async helpersHandle (file:///var/task/vercel/path0/apps/client/.svelte-kit/output/server/chunks/hooks.server.js:1181:18)
at async respond (file:///var/task/vercel/path0/apps/client/.svelte-kit/output/server/index.js:2638:22)
at async fetch (file:///var/task/vercel/path0/apps/client/.svelte-kit/output/server/index.js:2388:26)
"@sveltejs/adapter-vercel": "3.1.0",
"@sveltejs/kit": "1.30.4",
"svelte": "4.2.12",
And Node.js 20.x on Vercel.
Same issue here - reroute works locally, but breaks in prod on Vercel.
Anyone developed a fix or workaround for this?
Our alternative is to use a NextJS micro-app for handling the transparent rerouting.
Oh man I'm really looking forward to a fix.
Has anyone investigated what @LorisSigrist's idea of implementing reroute in Vercel Middleware would involve?
With our hack NextJS reroute() mock micro-app, I have to use data-sveltekit-reload
on every internal SvelteKit link for routes that are transparently proxied/rewritten, which forces a full-page refresh.
Now I'm seeing where the Vercel docs say you can't use Edge Middleware with SvelteKit for doing URL rewrites:
https://vercel.com/docs/frameworks/sveltekit#edge-middleware
Edge Middleware is useful for modifying responses before they're sent to a user. We recommend using SvelteKit's server hooks to modify responses. Due to SvelteKit's client-side rendering, you cannot use Vercel's Edge Middleware with SvelteKit.
So, hm, anyone have any other ideas? Is there a way to get reroute()
to work on Vercel?
In lieu of this, I'm considering going to a monorepo setup, and splitting off one major route category into another SvelteKit app, as a more robust workaround than the NextJS middleware setup we have currently, which will allow us to preserve snappy SvelteKit routing, preloads and page transitions. Might be a good solution for now!
Going to assume this is an issue for the netlify adapter too (and any adapters that split up the routes into different functions).
Also, if we do use a middleware to reroute the request url before it checks the static config to run the correct vercel function, we would also need a way to preserve the original url too?
Here's a POC of a Vercel edge middleware that reroutes given the following src/hooks.ts
file.
// src/hooks.ts
import type { Reroute } from '@sveltejs/kit';
const translated: Record<string, string> = {
'/en/about': '/en/about',
'/de/ueber-uns': '/de/about',
'/fr/a-propos': '/fr/about',
};
export const reroute: Reroute = ({ url }) => {
if (url.pathname in translated) {
return translated[url.pathname];
}
};
https://11879.vercel.app/en/about is rerouted to the /about
route
.vercel/output/config.json
{
"version": 3,
"routes": [
{
"src": "/_app/immutable/.+",
"headers": {
"cache-control": "public, immutable, max-age=31536000"
}
},
{
"handle": "filesystem"
},
{
"src": "/(.*)",
"middlewarePath": "reroute",
"continue": true
},
{
"src": "^/?(?:/__data.json)?$",
"dest": "/fn-0"
},
{
"src": "^/about/?(?:/__data.json)?$",
"dest": "/fn-1"
},
{
"src": "/.*",
"dest": "/fn"
}
],
"overrides": {}
}
.vercel/output/functions/reroute.func/index.js
import { reroute } from './hooks.js';
// see https://vercel.com/docs/functions/edge-middleware/middleware-api#rewrites
/**
* https://github.com/vercel/vercel/blob/4337ea0654c4ee2c91c4464540f879d43da6696f/packages/edge/src/middleware-helpers.ts#L38-L55
* @param {*} init
* @param {Headers} headers
*/
function handleMiddlewareField(init, headers) {
if (init?.request?.headers) {
if (!(init.request.headers instanceof Headers)) {
throw new Error('request.headers must be an instance of Headers');
}
const keys = [];
for (const [key, value] of init.request.headers) {
headers.set('x-middleware-request-' + key, value);
keys.push(key);
}
headers.set('x-middleware-override-headers', keys.join(','));
}
}
/**
* https://github.com/vercel/vercel/blob/4337ea0654c4ee2c91c4464540f879d43da6696f/packages/edge/src/middleware-helpers.ts#L101-L114
* @param {string | URL} destination
* @returns {Response}
*/
export function rewrite(destination) {
const headers = new Headers({});
headers.set('x-middleware-rewrite', String(destination));
handleMiddlewareField(undefined, headers);
return new Response(null, {
headers
});
}
/**
* @param {Request} request
* @returns {Response}
*/
export default function middleware(request) {
const pathname = reroute({ url: new URL(request.url) });
return rewrite(new URL(pathname, request.url));
}
EDIT: Added a draft PR below.
Describe the bug
An App that's deployed to vercel using
@sveltejs/adapter-vercel
will break if it is both:reroute
hooksplit: true
When hitting a route that should get rerouted, it will instead return a 404.
This has caused the localised routing provided by
@inlang/paraglide-sveltekit
to break when deployed to Vercel. opral/inlang-paraglide-js#32Reproduction
Repo: https://github.com/LorisSigrist/sveltekit-adapter-vercel-rerotute-bug-reproduction Deployment: https://sveltekit-adapter-vercel-rerotute-bug-reproduction.vercel.app/
The route
/some-page
should get rerouted to/
, but isn't in production. Instead a 404 is returnedLogs
No response
System Info
Severity
blocking all usage of SvelteKit (on Vercel)
Additional Information
No response