Background
I need to serve some JS files from my SvelteKit project, with a URL of let's say https://foo.bar/public/<filename>.js
. They are intended for use by other hosts, so I need permissive CORS headers.
Placing those files in /static/public
doesn't give me the permissive CORS headers I need, so I created server-side handler in /src/routes/public/[filename]/+server.ts
which reads <filename>.js
from disk and sets the correct headers.
That approach worked perfectly, until I realised (separate to this work) that my Docker image contained the unbuilt source code along with the build output. For obvious reasons, I removed the source code so that the Docker image now only contains the output of npm build
(plus any runtime dependencies).
This work broke .../public/[filename]/+server.ts
, as I was reading <filename>.js
from disk using a path which referenced their location in /src
, a path which no longer exists in the Docker image.
Attempts
Bypass the build process
I could just include the files as-is in my Docker image at a path outside of the SvelteKit build output and read them from disk at that path, but I then don't get the benefit of any of the packaging that SvelteKit does when building my assets (e.g. compression).
Use a manual path
I can figure out the correct path in the build output for <filename>.js
manually, but that's brittle and only works when I'm running the pre-built project (i.e. only if I do npm build; npm preview
, and not if I do npm dev
).
Vite resolve.alias
In theory I could create a new directory for my <filename>.js
files, then add that to the vite.config.ts
:
{
...,
resolve: {
alias: {
$publicjs: '/publicjs'
}
}
}
... and then reference the files using the alias, e.g.:
readFile(`$publicjs/{params.filename}`)
However, when building, Vite does not rewrite $publicjs
to the correct path as expected.
Serve as static, request, attach headers
For now I have a quick fix in place, which is to:
- place the files in
/static/__public/
, where they will be served by SvelteKit at/__public/<filename>.js
without the correct CORS headers - have my
.../public/[filename]/+server.ts
make a fetch to/__public/<filename>.js
, manipulate the headers in the response and send it on its way, i.e.:
// In /src/routes/public/[filename]/+server.ts
export const GET = (async ({ fetch, url, params }) => {
const response = await fetch(new URL(`/__public/${params.filename}`, url.origin));
const headers = {
...response.headers,
...specialCorsHeaders
};
return new Response(response.body, {
headers
});
}) satisfies RequestHandler;
While it does work, this is suboptimal:
- I have to make an extra request
- The files are being served on two paths:
/__public/<filename>.js
without permissive CORS headers, and/public/<filename>.js
with the correct headers.
Possible solutions
- move the files into
/static/public
and find a way to set specific headers for the response? - move the files to
/src/lib/
or elsewhere and find a way get the path in.../public/[filename]/+server.ts
?
Is there a better approach I'm not considering?