sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
17.88k stars 1.8k forks source link

Dev server does not apply base path correctly #2958

Closed andycarlberg closed 1 year ago

andycarlberg commented 2 years ago

Describe the bug

I'm using a code-server cloud environment to develop a SvelteKit project. In order to access the dev server, a proxy is provided that uses a subpath to proxy the dev server port (see docs. This leads me to need a base path to be set for the dev server.

If I set kit.paths.base as stated in the documentation, the first page load works correctly but the import statements are relative to the root which returns a 404, correctly, because those files are not available without the proxy. If I run build and preview everything works as expected since the base path is built into the compiled project.

Expected behavior All paths in the dev server reference the base path instead of being relative to the root domain.

Reproduction

  1. Create a new SvelteKit project
  2. Set kit.paths.base to a non-root path
  3. Run the dev server

Expected result All import statements look for paths with the base path or relative to the base path

Actual result Module import statements are relative to the root

Example image image

Logs

GEThttp://domain.tld/.svelte-kit/dev/runtime/internal/start.js
[HTTP/1.1 404 Not Found 8ms]

Loading module from “http://domain.tld/.svelte-kit/dev/runtime/internal/start.js” was blocked because of a disallowed MIME type (“application/json”). 3000
Loading failed for the module with source “http://domain.tld/.svelte-kit/dev/runtime/internal/start.js”. 3000:13:1
GEThttp://domain.tld/favicon.png
[HTTP/1.1 404 Not Found 6ms]

System Info

System:
    OS: Linux 5.10 Ubuntu 20.04.3 LTS (Focal Fossa)
    CPU: (12) x64 Intel(R) Core(TM) i5-10400 CPU @ 2.90GHz
    Memory: 283.55 MB / 15.32 GB
    Container: Yes
    Shell: 5.0.17 - /bin/bash
  Binaries:
    Node: 14.18.2 - /usr/bin/node
    Yarn: 1.22.15 - /usr/bin/yarn
    npm: 6.14.15 - /usr/bin/npm
  npmPackages:
    @sveltejs/kit: ^1.0.0-next.201 => 1.0.0-next.201 
    svelte: ^3.42.6 => 3.44.2

Severity

annoyance

Additional Information

I've been using the absproxy method with code-server. This passes the full path with the /absproxy/3000 portion intact. This seems like the correct approach for usage with kit.paths.base. I think this method would work fine if the dev server accounted for it when building the pages.

However, there is also the proxy method. The proxy method strips of the proxy subpath before passing the request to the dev server. Thus, on the dev server, all the paths are relative to root. If there was a way to specify a subpath only for use on the client side, this may also be a reasonable solution.

I've made some inline edits to the @sveltejs/kit package in node_modules and was able to get the proxy method working. It would require a config field to set it, of course. Obviously, not everyone is working in a cloud server 😄

andycarlberg commented 2 years ago

Decided to see if I could fix this myself. After digging in it looks like this might actually be a Vite issue, not a SvelteKit issue.

It's possible that SvelteKit may need additional updates beyond the fix for Vite as well.

Bastian commented 2 years ago

I'm having the same issue. My dev server is running behind a Traefik Reverse Proxy and thus it fails to resolve the .svelte-kit/* files which are ignoring the kit.paths.base setting: image

This is the config with the kit.paths.base set to /demo:

import adapter from '@sveltejs/adapter-node';
import preprocess from 'svelte-preprocess';

/** @type {import('@sveltejs/kit').Config} */
const config = {
    // Consult https://github.com/sveltejs/svelte-preprocess
    // for more information about preprocessors
    preprocess: [
        preprocess({
            postcss: true
        })
    ],

    kit: {
        adapter: adapter(),

        // hydrate the <div id="svelte"> element in src/app.html
        target: '#svelte',
        ssr: true,
        trailingSlash: 'ignore',
        paths: {
            base: '/demo'
        }
    }
};

export default config;
andycarlberg commented 2 years ago

@Bastian is correct, this is not actually a Vite issue as I first suspected. It does seem to be specific to SvelteKit. So I'll keep looking but I'm probably out of my depth here for a quick fix.

I started looking at it as a Vite problem because I always seemed to come back to Vite when trying to trace the issue through SvelteKit. I must have missed something though since a vanilla Vite project applies the base path as expected.

rassie commented 2 years ago

@andycarlberg

I've made some inline edits to the @sveltejs/kit package in node_modules and was able to get the proxy method working. It would require a config field to set it, of course. Obviously, not everyone is working in a cloud server smile

Could you share a gist of what you've changed?

andycarlberg commented 2 years ago

@rassie I've pushed up some of my work-in-progress tinkering with the change essentially here.

This applies the base path prefix to the entry file. This is not a complete fix because I'm having trouble finding where these paths should actually be set. It's not a complete solution, more proof that there's an issue to be addressed I think.

andycarlberg commented 2 years ago

I feel like I'm on the right track here with this change.

It correctly outputs the file path with the base prefix but it 404's when looking for that start.js file. In debugging, it seems like that file is treated differently than other requests since the SvelteKit middleware doesn't process that file without my change (i.e. root-relative).

Any hints on where I might look to get it to recognize that file as the special start file even if it has the prefix?

bjaskj commented 2 years ago

I spent some time on something I think is similar, but I did not manage to figure out a fix for it.

I'm trying to use svelte kit via proxy server, and it works fine with static build and serve via other folder than root (having kit.paths.base) but it goes around and tries to include files that are in "root", like node modules etc. I only got it working if I set the base in vite config in the kit package and also modified the prefix, see below:

I think it boils down to the core/dev/index.js having a hardcoded value of "/", I tried playing around with this with some success but I ran into other issues trying to find a way to set it.

I also looked into prefix set to value of "" in this core/dev/plugin.js

This makes the paths to the script resources etc used in start method inside runtime/server/page/render.js

Maybe someone can help with a fix on this?

johnnysprinkles commented 2 years ago

Not sure if this stackoverflow question is related: https://stackoverflow.com/questions/69378392/sveltekit-base-url-for-subdirectory-throws-404 They don't seem to be using a proxy though. I am using a proxy with stunnel and running into this issue, just working around with conditional svelteconfig, like:

{
  kit: {
    paths: {
      base: process.env.NODE_ENV === 'development' ? undefined : '/mybase',
    },
  },
}

Edit: The downside of this though is navigation, if I have a header on various pages at different levels in the tree, and it has links or "goto" calls, it'll need an absolute path which can't work in both prod and dev.

johnnysprinkles commented 2 years ago

So it turns out this is only the index route that fails to load, any deeper path works fine.

bjaskj commented 2 years ago

What happen to me was that if I set kit.paths.base and then also the vite base path, which is hardcoded to '/' in kit, then I have to use /mypath/mypath to get to index. So something is a bit bork. Also if I managed to get it use /mypath, then all the other paths (node_modules, svelte kit etc) would still go to root/hostname http://localhost/.svelte-kit.

johnnysprinkles commented 2 years ago

So I just wanted to clarify and provide simple repo steps, and make sure I'm actually in the right bug (I can open a new one if not.) This doesn't have anything to do with proxies or missing js/css assets, it's actually that the main HTML document is 404 when using a base path and running in dev mode.

  1. Init a brand new SvelteKit app with npm init svelte@next sv which gives as of now, SvelteKit v1.0.0-next.230
  2. Choose the Demo App
  3. cd sv; npm i
  4. npm run dev
  5. Everything works fine
  6. Kill that, edit svelte.config.js to include kit.paths.base = '/foo'
  7. Start up again with npm run dev
  8. Note that both http://localhost:3000 and http://localhost:3000/foo give you a 404.
  9. Note that deeper paths do work however, i.e. http://localhost:3000/foo/about
benmccann commented 2 years ago

Note that both http://localhost:3000 and http://localhost:3000/foo give you a 404.

http://localhost:3000/foo works for me. Closing as fixed

rassie commented 2 years ago

@benmccann pardon me asking, maybe I'm missing something here, but what exactly has been fixed? You basically just said "works for me" (which is fine and probably true for the example above), but has there been any change addressing the original problem and the comments above?

bjaskj commented 2 years ago

I would also like to see this fixed, I can't use a dev env for some projects because of this issue.

johnnysprinkles commented 2 years ago

Thanks @benmccann I just tried with SvelteKit v1.0.0-next.236 and confirmed it's working. And to make sure I wasn't just doing something wrong before, I downgraded sveltekit to next.230 and observed the 404 again, so it seems to have been fixed.

There is a minor issue where the Demo app isn't prepending its static asset paths with $app/paths.base, so there's some broken images. I might file a separate super low priority bug for that.

It looks like I did hijack OPs original issue, sorry about that. Reading through it sounds like they want to slightly expand the meaning of kit.paths.base to skip over the base path in all contexts, even in local development. Can we re-open this bug? Even if not targeted for 1.0 it seems like a shame to make people fork one-liner edits to unblock themselves.

johnnysprinkles commented 2 years ago

Also, sorry @benmccann if I was kind of a jerk last year, I was pulling my hair out trying to make SvelteKit a workable option for a very large project at Google, but that never did go anywhere and I ended up quitting Google. Onward!

rassie commented 2 years ago

@johnnysprinkles sorry to be blunt, and I don't think you intended this, but I think you derailed this issue for an unrelated problem.

@benmccann the problem in question still exists and it's a different one. In the example above, localhost:3000/foo is working, but the reason why it's working is because localhost:3000/.svelte-kit is still available without a proxy. If you put a proxy in front and only forward /foo to the server, you'd only forward requests to /foo, but not /.svelte-kit, you'll be getting 404 errors for SvelteKit runtime and nothing will work at all. The issue here is that kit.paths.base should be applied to /.svelte-kit too, which it's currently not.

You can easily verify it with the repro above, but look into Developer Tools, where you should see something like this:

image

If /.svelte-kit is not properly forwarded as /foo/.svelte-kit, nothing will work. And forwarding just /.svelte-kit is not a solution, since the whole reason people use proxies is to host multiple sites on the same domain, so most people need a /foo with /foo/.svelte-kit and a /bar with /bar/.svelte-kit.

andycarlberg commented 2 years ago

As OP, i wanted to verify that @rassie is correct. Their comment shows the issue I was originally trying to deal with. I haven't personally made any further progress on it but would agree the issue is not fixed.

tecoad commented 2 years ago

I confirm this issue, I was meant to user sveltekit on a /blog subdirectory, however all assets still load from root, when it should rewrite to kit.paths.base. Unfortunately will have to stick with nextjs for this project.

Beiri22 commented 2 years ago

Might be the same problem in my situation: I try to access the dev server via a reverse proxy. I have tried kit.paths.base and kit.vite.server.origin. Nothing works to set the sub-path associated on the proxy machine. Still showing import { start } from "/@fs/ which should use some subdirectory...

davidroeca commented 2 years ago

My team uses nginx + docker-compose to set up a dev environment with multiple APIs/frontends. Since we only have one svelte-kit project, this is ok for now, but it is not ideal. In order to get the current version of svelte-kit to work in this set up, we need to set up nginx with the below configuration. I'd expect that analogous configuration is required in whatever reverse proxy environment is being used. (HMR config is separate, but easier to implement because it's on a different port).

        location /svelte-kit-ui-base-path {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }
        location  /@fs {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }
        location /.svelte-kit {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }
        location /node_modules {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }
        location /@vite/client {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }
        location /src {
            set $target "http://svelte_kit_ui:3000";
            proxy_pass $target;
        }

I'd view this as a work-around, not a long-term solution. Hopefully this saves time for anyone else having trouble with this.

It would be very nice to be able to prefix every route above with /svelte-kit-ui-base-path.

mosherbrian commented 2 years ago

I am running a svelte-kit dev server behind a code-server proxy and can confirm that this is still an issue. Any fix or workaround available?

AlbertMarashi commented 2 years ago

I am still getting this issue. Any fixes?

Edit bug seemed to have fixed itself (possibly by updating my sveltekit)

squelix commented 2 years ago

I am still getting this issue. Any fixes?

Rich-Harris commented 2 years ago

Pretty sure this is fixed now — are people still experiencing it with latest versions? If so, a repro would be much appreciated

Beiri22 commented 2 years ago

I'll try out on my example project as soon as possible.

Beiri22 commented 2 years ago

@Rich-Harris The normal case works. But we have a special case here. The application is working with Shibboleth authentication that is carried out by an reverse proxy server. But all the "/@fs/..."-Links are not put under the base path. So I cannot use the dev mode. Is there any way to approach this behaviour?

By the way - in reverse proxy mode it would be nice to have an option that the base path is only applied when creating the pages. What do I mean: The page has a link to "/base/path/some.page", the reverse proxy removes the base path, so the server serves the document without the base path "/some.page"

andycarlberg commented 2 years ago

I just tried it out on my project with svelte-kit, 1.0.0-next.335

I'm still having the problem. I think @Beiri22 is correct, the /@fs/... paths don't have the base path so it's unable to load those supporting files in dev mode.

Rich-Harris commented 2 years ago

How would I go about reproducing this?

andycarlberg commented 2 years ago
  1. Create a new SvelteKit project
  2. Set kit.paths.base to a non-root path
  3. Run the dev server

If you're just running the dev server locally, you will be able to navigate the project. Check the browser dev tools and note the paths that are being requested. The /@fs/... paths don't include the base path prefix. This is the actual issue that needs to be addressed.

It works for local development because the local dev server has access to both the base path and the non-prefixed paths. It becomes a problem for development behind a proxy where the base path is necessary to access any files on the dev server. In my case, this is surfaced when I'm trying to use code-server to develop. The dev server isn't accessible locally because it isn't running locally. Instead, I access it through a proxied base path. It works for the initial page load but those /@fs/... paths can't be reached without the base path prefix.

Beiri22 commented 2 years ago

I not 100% sure, but could it be that the /@fs/-paths are generated by vite rather than sveltekit?

rassie commented 2 years ago

/@fs/ paths aren't the only ones, there is also /.svelte-kit/, which I'm pretty sure does not come from Vite ;)

Beiri22 commented 2 years ago

You're right. But maybe the issue must be targeted here and at vite's. btw. could you reproduce it @Rich-Harris ?

till commented 1 year ago
  1. Create a new SvelteKit project
  2. Set kit.paths.base to a non-root path
  3. Run the dev server

If you're just running the dev server locally, you will be able to navigate the project. Check the browser dev tools and note the paths that are being requested. The /@fs/... paths don't include the base path prefix. This is the actual issue that needs to be addressed.

It works for local development because the local dev server has access to both the base path and the non-prefixed paths. It becomes a problem for development behind a proxy where the base path is necessary to access any files on the dev server. In my case, this is surfaced when I'm trying to use code-server to develop. The dev server isn't accessible locally because it isn't running locally. Instead, I access it through a proxied base path. It works for the initial page load but those /@fs/... paths can't be reached without the base path prefix.

I can confirm this. I did a npm update just now.

What works is: http://localhost:port/my-prefix

What doesn't work is when it sits behind a proxy: http://fancy.host.127.0.0.1.nip.io/my-prefix

Console shows a 404 in start.ts:

http://fancy.host.127.0.0.1.nip.io/@fs/Users/till/workspaces/app/src/.svelte-kit/runtime/client/start.js
Beiri22 commented 1 year ago

It's really annoying. I need to run the programm behind a reverse proxy in order get the correct authentication information. I would run "dev" mode, but that does not work in that setup. So i need to run buikd and preview after each change in code.

till commented 1 year ago

It's really annoying. I need to run the programm behind a reverse proxy in order get the correct authentication information. I would run "dev" mode, but that does not work in that setup. So i need to run buikd and preview after each change in code.

Above 👆 there are the routes you need to add to your proxy. Posted as an example for nginx. Adapt, and it works. Do you need any help with another proxy?

Beiri22 commented 1 year ago

I do only have access to a sub path, root @fs is no option...

rassie commented 1 year ago

It's really annoying. I need to run the programm behind a reverse proxy in order get the correct authentication information. I would run "dev" mode, but that does not work in that setup. So i need to run buikd and preview after each change in code.

Above point_up_2 there are the routes you need to add to your proxy. Posted as an example for nginx. Adapt, and it works. Do you need any help with another proxy?

Only works for one proxied site. Two or more is currently impossible.

Beiri22 commented 1 year ago

In a setup with a reverse proxy, the "external base path" might or might not be preserved when forwarded to the server itself. So it would be nice to have either a) thw base paths: an external that is used when creating all the links and an internal that is used when interpreting the requests b) a flag that allows for the fact that the proxy might remove the external base path when relaying the request to the server.

elron commented 1 year ago

This issue still exists.

When I add this kit.paths

    const base = '/wp-content/plugins/lettering-product-shortcode-plugin';
    config.kit.paths = {
        base,
        assets: 'https://staging.hafonton.co.il' + base
    };

It totally ignores it and tries to load from root domain (/_app/immutable/assets/index-f01e1744.css) instead of https://staging.hafonton.co.il/wp-content/plugins/lettering-product-shortcode-plugin/_app/immutable/assets/index-f01e1744.css

And it shows this error message:

Unable to preload CSS for /_app/immutable/assets/index-f01e1744.css Error: Unable to preload CSS for /_app/immutable/assets/index-f01e1744.css at HTMLLinkElement.<anonymous> (https://staging.hafonton.co.il/wp-content/plugins/lettering-product-shortcode-plugin/_app/immutable/start-3d8db190.js:1:12256)

JohnRSim commented 1 year ago
  1. Create a new SvelteKit project
  2. Set kit.paths.base to a non-root path
  3. Run the dev server

If you're just running the dev server locally, you will be able to navigate the project. Check the browser dev tools and note the paths that are being requested. The /@fs/... paths don't include the base path prefix. This is the actual issue that needs to be addressed.

It works for local development because the local dev server has access to both the base path and the non-prefixed paths. It becomes a problem for development behind a proxy where the base path is necessary to access any files on the dev server. In my case, this is surfaced when I'm trying to use code-server to develop. The dev server isn't accessible locally because it isn't running locally. Instead, I access it through a proxied base path. It works for the initial page load but those /@fs/... paths can't be reached without the base path prefix.

Has this issue come back - just did a fresh install and set base path..

image

/** @type {import('@sveltejs/kit').Config} */
import adapter from '@sveltejs/adapter-static';
import { mdsvex } from 'mdsvex';
import preprocess from 'svelte-preprocess';

const config = {
    extensions: ['.svelte', '.md', '.svelte.md'],
    preprocess: [
        mdsvex({ extensions: ['.svelte.md', '.md', '.svx'] }),
        preprocess({
            postcss: true,
            scss: {
                prependData: "@import 'src/lib/styles/variables.scss';",
            },
        }),
    ],
    kit: {
        adapter: adapter({ precompress: true }),
        paths: {
            base: '/_themes/_components/BB-Custom-Form/publish/assets',
        },
    },
};

export default config;
JohnRSim commented 1 year ago

Ahh sorry was access through proxy - accessing direct works..

BenediktAllendorf commented 1 year ago

I didn't find a working configuration, but I've managed to patch the source code to work as desired.

I think there are two parts to this:

  1. The import of start.js must use the correct (base-)prefix.
  2. The base for Vite must be set correctly instead of the hardcoded ./.

It worked as expected when adding my prefix ( web) into those two lines. I could run my SvelteKit-project at localhost:3000/ and access it via my proxy at localhost:9999/web. Please note that I didn't add paths.base to svelte.config.js because then I would have had localhost:3000/web/web and localhost:9999:/web/web ( I guess that's an artifact of messing around).

I feel SvelteKit's understanding/usage of "base" differs from Vite's - how is it supposed to work here? I'm willing to create a PR for this, but I'd need some guidance (as in, is this even reasonable? How should this be tested?).

benmccann commented 1 year ago

I tried passing SvelteKit's base path to Vite awhile back, but found out that it's not currently possible because Vite handles the base path and static file serving in some ways that are different. We would need to resolve the following issues in Vite to make it possible to handle this correctly in SvelteKit:

I would very much welcome PRs for those issues in the Vite repo. ViteConf is today. Vite 3.2 will be released later this week I believe and then work on Vite 4 can begin, which may enable us to make these changes, which would probably all be breaking changes. I can help check with the Vite team to ensure they're open to making these changes and agree on an approach, but would love help with implementing them.

BenediktAllendorf commented 1 year ago

I'm eager to help with the implementation (the alternative would be for us to maintain a fork and I'd rather see this being fixed upstream), but I'm cannot really asses right now what/where exactly should be changed. So if you, @benmccann, check with the Vite team, that would be great!

benmccann commented 1 year ago

I talked to the Vite team this morning and made quite a bit of progress on a plan for moving forward. I sent https://github.com/sveltejs/kit/pull/7343 to address one of the items. I also sent https://github.com/vitejs/vite/pull/10590 to address a good chunk of https://github.com/vitejs/vite/issues/9236. @BenediktAllendorf I'll ping you after https://github.com/vitejs/vite/pull/10590 gets merged and perhaps if you're still interested you can finish the rest of https://github.com/vitejs/vite/issues/9236 which would be the last blocker.

benmccann commented 1 year ago

https://github.com/vitejs/vite/pull/10590 has been merged now. @BenediktAllendorf let me know if you'd be able to take a look at https://github.com/vitejs/vite/issues/9236. If we can get that fixed it should be the last blocker to setting the base path in Vite and removing our file serving in favor of Vite's. I updated that ticket with some details to help with getting started.

rassie commented 1 year ago

Seems like those issues have been fixed. Is anything else necessary to be able to say that Vite 4 will solve this?

benmccann commented 1 year ago

There is a Vite 4 branch of SvelteKit: https://github.com/sveltejs/kit/pull/7543. I'd appreciate if folks could test against it and let me know if it is fixed or not

alexbjorlig commented 1 year ago

I'm trying to figure out why I can't serve Sveltekit from a different directory - is this issue the culprit?