0

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?

sam-w
  • 7,478
  • 1
  • 47
  • 77

0 Answers0