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

base_path needed for deploy, but breaks local serve #2285

Open
hkBst opened this issue Apr 9, 2024 · 3 comments
Open

base_path needed for deploy, but breaks local serve #2285

hkBst opened this issue Apr 9, 2024 · 3 comments
Labels
bug Something isn't working cli Related to the dioxus-cli program

Comments

@hkBst
Copy link

hkBst commented Apr 9, 2024

Problem

I need to set [web.app]base_path in Dioxus.toml to get deployment on Github Pages working. But then locally the app refuses to work as it is replaced by an error message ("Outside of the base path: /your-path"). Is it possible to get both to work?

Environment:

  • Dioxus version: 0.5.1
  • Rust version: 1.76.0
  • OS info: Linux
  • App platform: web
@ealmloff ealmloff added bug Something isn't working cli Related to the dioxus-cli program labels Apr 9, 2024
@s1gtrap
Copy link

s1gtrap commented May 10, 2024

I had some success using the latest CLI instead (thanks to #2381):

cargo install --git https://github.com/DioxusLabs/dioxus.git dioxus-cli

With that, fetching http://localhost:8080/<base_path> seems to respond correctly, although http://localhost:8080/<base_path>/ still yields Outside of the base path: /<base_path> (is this intended?)

This wasn't all the way there in my case as assets weren't loading properly. Naturally, as there was no trailing / in the URL, all relatively addressed assets were being loaded from the root instead of after the base_path, despite them (correctly) only being served after the base_path.

So I tried adding a trailing / in packages/cli/src/server/web/server.rs and it's actually working as intended now. In fact, it seems to be working much better, as even http://localhost:8080/<base_path> is redirected to http://localhost:8080/<base_path>/ ensuring all assets are available regardless of how the address is entered.

It's available here: https://github.com/s1gtrap/dioxus/tree/fix-relative-assets-w-base-path but I'll create a PR in a sec.

@pyrrho
Copy link
Contributor

pyrrho commented May 13, 2024

@s1gtrap I can share some details from my digging for #2381 and #2395

... fetching http://localhost:8080/<base_path> seems to respond correctly, although http://localhost:8080/<base_path>/ still yields Outside of the base path: /<base_path> (is this intended?)

From what I can see, this isn't intended but I don't think the Dioxus team has any (direct) say in the matter. From what I can tell from some issues open in tokio-rs/axum, there's a surprising (TBD if that means "bug," I guess?) interaction between axum::routing::Router::nest and axum::routing::Router::fallback; given a subrouter with a fallback, nesting the subrouter under /<some_path> and fetching /<some_path>/ will not hit the subrouter's fallback (it may hit the parent's, though, if one exists). Because the Dioxus server uses that pattern for nesting /<base_path>, we're stuck with that /<base_path>/ is outside of /<base_path> nonsense.

I've put together a little demo axum server to demonstrate this. I'll push it to GH and edit this comment w/ a link in a few.

Your comment from #2403,

... requests to /<base_path> are redirected to /<base_path>/ automatically.

This really surprised me, as it's not the behavior I've observed in my puttering. May I ask what OS you're running this on? I'd love to see a minimal reproduction of that behavior.

Naturally, as there was no trailing / in the URL, all relatively addressed assets were being loaded from the root instead of after the base_path,

My understanding is that there's no real way of getting around this, and that (for this style of "single"-page app) assets need to be served as absolute paths. I may well be wrong, and I'd love to be corrected as it's been a few years since I've written any real React, but consider deep links. Given a /<base_path> and a dioxus_router_macro::Routable enum with a / and a /dx/routed/path route set, adding the trailing slash to /<base_path> will only get assets to be correctly served when users navigate to the root of the SPA -- to the / enum member. If someone navigates directly to /base_path/dx/routed/path, the axum fallback will directly serve the dx-generated index.html, relative asset paths included. Instead of looking for some css in /base_path/assets/my.css, the browser would be looking in /base_path/dx/routed/assets/my.css. Again, my understanding is that this is true for all browser-routed web apps, not just dx.

That said, I think there's room for improvement in the dx server to better handle assets in apps that include a base_path. I've not gotten to fussing with the dx HTML yet, but it's on my list to look at as I experiment.

And a final note, I do have a workaround for the /<base_path>/ is outside of /<base_path> thing. This code is under-baked, but I think it demonstrates the idea pretty well.

Folded code b/c this comment is already long enough

This code is offered as-is, probably buggy, MIT, YMMV, ETC.

/// Extensions for the Axum [`Router`] type.
pub trait AxumRouterExt<S>
where
    S: Clone + Send + Sync + 'static,
{
    /// Nest a Router that is expected to include a fallback.
    ///
    /// This function is designed to mitigate the issues (or perhaps surprises)
    /// described in [tokio-rs/axum#2659] by first nesting the given `router` as
    /// per [`Router::nest`], and then adding an additional route that redirects
    /// `{path}/` to `{path}`.
    ///
    /// [tokio-rs/axum#2659]: https://github.com/tokio-rs/axum/issues/2659#issuecomment-2016666385
    fn nest_hosting_fallback(
        self,
        path: impl AsRef<str>,
        router: Router<S>,
    ) -> Self;
}
impl<S> AxumRouterExt<S> for Router<S>
where
    S: Clone + Send + Sync + 'static,
{
    fn nest_hosting_fallback(
        self,
        path: impl AsRef<str>,
        router: Router<S>,
    ) -> Self {
        // TODO: This will break if path has a trailing slash. Should we panic
        //       if that happens? Let users configure nonsense routes? Make this
        //       fallible?
        let path = path.as_ref();
        let path_trailing_slash = format!("{}/", path);

        self.route(
            &path_trailing_slash,
            get({
                let path = path.to_owned();
                // Capture raw query params and forward them in the redirect.
                |RawQuery(params): RawQuery| async move {
                    let target = if let Some(params) = params {
                        format!("{path}?{params}")
                    } else {
                        format!("{path}")
                    };
                    Redirect::permanent(target.as_ref())
                }
            }),
        )
        .nest(path, router)
    }
}

@Gisleburt
Copy link

I'm also running into the same problem, two potential work arounds:

  1. Use something like static-web-server to serve the actual built version locally (downside, you lose the hot-reloading)
  2. Comment out the base path, use CD (eg GHA) to put it back in again before building (downside, I'm too lazy to set up CD despite the fact I'm now running ~5 separate Dioxus sites all of which just have their generated code committed in a /docs directory 😅)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working cli Related to the dioxus-cli program
Projects
None yet
Development

No branches or pull requests

5 participants