Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make adapter-node base path configurable via environment variable #7242

Open
benmccann opened this issue Oct 12, 2022 · 6 comments
Open

make adapter-node base path configurable via environment variable #7242

benmccann opened this issue Oct 12, 2022 · 6 comments
Labels
feature request New feature or request p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc.
Milestone

Comments

@benmccann
Copy link
Member

When generating a static site we ultimately will be placing it either in the correct folder OR preferably behind a load-balancing reverse proxy that strips off the prefix and have it served from the root. So the prefix should not exist in the build folder at all but the code will need to know to add the prefix when referring to assets.

When generating a dynamic site it can be passed environment variables (or perhaps read a config file) where it gets its base prefix. In the same way the site could exist behind a reverse proxy that strips off the prefix OR it'll handle the prefix itself. It matters not as this is an implementation detail of the adapter. The code needs to know to add the prefix when referring to assets and presumably when doing SSR fetching it'll need to know to add/remove the prefix as necessary.

adapter-node uses Polka to serve its assets, executed with the following code:

const server = polka().use(
	// https://github.com/lukeed/polka/issues/173
	// @ts-ignore - nothing we can do about so just ignore it
	compression$1({ threshold: 0 }),
	handler
);

handler is provided as:

const handler = sequence(
	[
		serve(path.join(__dirname, '/client'), 31536000, true),
		serve(path.join(__dirname, '/static'), 0),
		serve(path.join(__dirname, '/prerendered'), 0),
		ssr
	].filter(Boolean)
);

The issue is that ssr will strip off base from the beginning of the URL but the three serve calls do not. The ssr function IMHO should not be doing this and instead everything should be mounted at the polka().use() call, something like this:

const server = polka().use(
        BASE_PATH,
	// https://github.com/lukeed/polka/issues/173
	// @ts-ignore - nothing we can do about so just ignore it
	compression$1({ threshold: 0 }),
	handler
);

where BASE_PATH would be set either by reading the config file or come in from an environment variable.

This way if I have a reverse proxy that strips prefixes I can have BASE_PATH set to '' but pass the actual base through a header like X-Forwarded-Prefix for when building URL's.

If I don't strip the prefix, then I can set BASE_PATH to the prefix so its handled inside Polka instead but otherwise the rest of the code remains the same.

Anyway, that's my 2c.

Originally posted by @bundabrg in #3726 (comment)

This overlaps a bit with #595

@dummdidumm
Copy link
Member

Adding another comment from #3726 which is relevant:

Oh, I really need this to be fixed. I cannot use the workaround mentioned earlier because my case is one level more complex as I need to use the generated middleware handler in another express server (directus). I cannot control exactly when to .use(handler) and they bind many other middlewares which means that I have to bind the sveltekit handler only to a single subpath (say /dashboard).

.use(handler) without setting paths.base

Both frontends (sveltekit and directus) are confused and nothing works...

.use(handler) with setting paths.base to /dashboard

Sveltekit frontend displays html pages but scripts are not found. But directus does not load correctly.

.use('/dashboard', handler) without setting paths.base

I can access the sveltekit frontend via /dashboard but internal links (href="{base}/about") are not working as base is empty and javascript cannot be loaded (urls do not contain /dashboard and thus are not handled by the middleware). Directus works without probems.

.use('/dashboard', handler) with setting paths.base to /dashboard

I can access kit via /dashboard/dashboard (yes duplicated) but the the about page is not available at /dashboard/about (which is build from href="{base}/about") but at /dashboard/dashboard/about. Basically I need to duplicate the base path. Strangely now the javascript files can be loaded correctly (at /dashboard/_app/immutable/start-e25cee58.js).

I found I can fix this by removing these lines

if (options.paths.base && !state.prerendering?.fallback) {
if (!decoded.startsWith(options.paths.base)) {
return new Response('Not found', { status: 404 });
}
decoded = decoded.slice(options.paths.base.length) || '/';
}

Now everything works as expected (i.e. /dashboard and /dashboard/about) at least with my minimal testing.

This is surely not the final solution as the dev server needs those lines and I guess the other adapters need them as well...


I got one step further by adding the base url to the request before passing it to the handler:

    app.use('/dashboard', (req, res, next) => {
      let requestProxy = new Proxy(req, {
        get(target, property) {
          if (property === 'url') {
            return target.baseUrl + (target.url === '/' ? '' : target.url);
          }

          return target[property];
        },
      });

      handler(requestProxy, res, next);
    });

Now the ssr function works correctly (because it strips the basepath we just added) but the static files are not correctly served (because sirv does not strip the basepath) as @bundabrg also noted in #3726 (comment)

Originally posted by @fehnomenal in #3726 (comment)

@benmccann benmccann changed the title feat: make adapter-node base path configurable via environment variable make adapter-node base path configurable via environment variable Oct 12, 2022
@benmccann benmccann added feature request New feature or request p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc. labels Oct 12, 2022
@benmccann benmccann added this to the whenever milestone Oct 12, 2022
@gregroyal
Copy link

Anyone have any workarounds to this issue? Its blocking me for dynamic path deployments if i dont know the base at build time

@sidharthramesh
Copy link

Same here

@Mr-Thack
Copy link

Mr-Thack commented May 14, 2024

I found this to work:

import CONFIG from "../svelte.config.js"
import { dev } from "$app/environment";
...
redirect(307, (dev? "" : CONFIG.paths.base) + "/normal/redirect");

Oh wait a second. I think I fixed it. If I reply below, then know that I've "fixed" it. If not, then try using this in your code.

@Mr-Thack
Copy link

nvm, it "works" but it causes like 100 recursive definition errors which (depending on the environment) could cause the build/ folder to be missing some very very important js files.

@Mr-Thack
Copy link

Ok, so I found another solution.
This solution will only work if you will be setting the base path at compile time. If you are doing it right before launching the executable, I think you could use dynamic env variables instead and manually route everything. Or perhaps intercept the default router.

So, for this method, you will need

  1. base.js - some file in your project root directory. Maybe you could also put it in $lib.
const BASE = "/new";
export default BASE;
  1. Modify svelte.config.js:
import BASE from "../base.js";
...
export config = {
  ...
  paths: {
    base: BASE,
    relative: false
  }
 ...
};
  1. And finally, modify +hooks.server.ts or whatever +page.server.ts:
// make sure to get the path right
import BASE from "../base.js";
...
redirect(307, BASE + "/login");

This works. But this is a work around, not a fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request p2-nice-to-have SvelteKit cannot be used by a small number of people, quality of life improvements, etc.
Projects
None yet
Development

No branches or pull requests

5 participants