leptos-rs / leptos

Build fast web applications with Rust.
https://leptos.dev
MIT License
16.38k stars 656 forks source link

Reverse proxy on a subfolder breaks hydration #3029

Closed chelahmy closed 4 weeks ago

chelahmy commented 1 month ago

Leptos-Axum works behind Apache2 reverse proxy, but not from a sub-folder.

We are using Apache2 to serve our websites. We want to create a service on a sub-folder such as https://mydomain.com/v2 using Leptos-Axum, which requires setting up a reverse proxy from Apache2 to Leptos-Axum. However, the server-side rendering did not recognize the '/v2' sub-folder. Hence, the '/pkg' files could not be loaded by the browser. We tried various configurations until we managed to get all the '/pkg' files loaded into the browser. And we managed to get wasm to execute on the browser but the hydration didn't work.

We also tried Leptos-Actix but the problem persisted.

We decided to run the service from a sub-domain such https://v2.mydomain.com through the same reverse proxy. And it works. But that is not what we wanted.

gbj commented 1 month ago

I don't think this has anything to do with this template per se, does it? As you note, it applies to the Actix template as well.

It sounds to me like what you're missing is probably the base prop on the Router and/or Routes component, so that the router knows that you are routing relative to some path other than /.

chelahmy commented 1 month ago

You are right. Nothing to do with this template directly. But I don't know which Leptos repo that deals with server-side rendering that generate links on every page to load js & wasm. This repo has something to do with ssr. Those generated links should include the base as you mentioned.

The environment variables does not include base:

LEPTOS_OUTPUT_NAME="start-axum" LEPTOS_SITE_ROOT="site" LEPTOS_SITE_PKG_DIR="pkg" LEPTOS_SITE_ADDR="127.0.0.1:3000" LEPTOS_RELOAD_PORT="3001"

Only LEPTOS_SITE_PKG_DIR is included in the generated links. I'm expecting something like LEPTOS_SITE_BASE. I'm running the server binary from the parent folder of LEPTOS_SITE_ROOT. Note: LEPTOS_SITE_PKG_DIR is both a logical path, and a physical child folder of LEPTOS_SITE_ROOT.

When you have environment variables like those above then Router base seems to be non-intuitive.

gbj commented 1 month ago

@chelahmy I have transferred this to the leptos repo.

It's unclear to me whether you're talking about loading the JS/WASM files, or the router behavior in the client, or both. My understanding from what you wrote above is that you were successfully loading the WASM files but the page was hydrating incorrectly due to the router base not being set.

If you want to control the path for the JS/WASM files to be loaded from, you can use the CDN_PKG_PATH environment variable (either at runtime or compile time) to set a path.

If you want to control the base for the router, you can use the base prop.

chelahmy commented 1 month ago

@gbj thank you for transferring this to the leptos repo.

I just want to add some more context. The following code was rendered by the server when I set LEPTOS_SITE_PKG_DIR="v2/pkg":

`

                <script type="module">
                    function idle(c) {
                        if ("requestIdleCallback" in window) {
                            window.requestIdleCallback(c);
                        } else {
                            c();
                        }
                    }
                    idle(() => {
                        import('/v2/pkg/mlm.js')
                            .then(mod => {
                                mod.default('/v2/pkg/mlm.wasm').then(() => mod.hydrate());
                            })
                    });
                </script>

`

Notice that all rendered links start with '/v2'. I knew that setting LEPTOS_SITE_PKG_DIR="v2/pkg" wasn't right. But I want the server to render it that way. Unfortunately, wasm could not hydrate the page. Maybe wasm didn't aware or '/v2'. I don't know.

If I set the router base to '/v2' will the server render all those links to start with '/v2'?

gbj commented 1 month ago

Those <link> tags all look correct to me, based on your description. Do they look correct to you? Do they load the JS/WASM successfully, or do they 404?

Unfortunately, wasm could not hydrate the page. Maybe wasm didn't aware or '/v2'

Do you mean that the WASM module could not load? Or do you mean that it loaded, and there was a hydration error?

If I set the router base to '/v2' will the server render all those links to start with '/v2'?

These things are completely unrelated to each other. But have you tried setting the router base?

chelahmy commented 1 month ago

Those tags all look correct to me, based on your description. Do they look correct to you? Do they load the JS/WASM successfully, or do they 404?

They look correct to me. They loaded JS/WASM successfully.

Do you mean that the WASM module could not load? Or do you mean that it loaded, and there was a hydration error?

WASM did load but with hydration errors, something like:

element with id 0-0-015 not found, ignoring it for hydration

These things are completely unrelated to each other. But have you tried setting the router base?

I did not set the router base because I think it is not related.

chelahmy commented 1 month ago

I made a mistake. When I set site-pkg-dir="v2/pkg", cargo-leptos REMOVED the 'target/site/pkg' folder and created 'target/site/v2/pkg' folder but did not generate JS/WASM in it. Only CSS had been generated.

Before I changed site-pkg-dir, it was building with default environment setting. I thought JS/WASM were generated once. So, I copied them to my server. For context, I was building on my notebook and then copied the binaries to the server. When I changed to site-pkg-dir="v2/pkg", cargo-leptos did not generate JS/WASM and did not panic. So, I thought everything was okay until just now I took a look at the 'target/site/v2/pkg' folder where there is no JS/WASM files.

It means I was using wrong JS/WASM files. But why missing JS/WASM in 'target/site/v2/pkg'?

chelahmy commented 1 month ago

The objective is that given base="/v2" somewhere, the server will prepend "/v2" on all links it rendered, and cargo-leptos would have compiled wasm appropriately. And router doesn't have to know about the base:

<link rel="modulepreload" href="/v2/pkg/mlm.js"> <link rel="preload" href="/v2/pkg/mlm.wasm" as="fetch" type="application/wasm" crossorigin=""> <script type="module"> function idle(c) { if ("requestIdleCallback" in window) { window.requestIdleCallback(c); } else { c(); } } idle(() => { import('/v2/pkg/mlm.js') .then(mod => { mod.default('/v2/pkg/mlm.wasm').then(() => mod.hydrate()); }) }); </script>

gbj commented 1 month ago

Here's what I will say: If you are able to provide a minimal, reproducible example of the problem you are facing, I am facing to work to debug it. Otherwise, there's very little that I can say to help because it's not clear to me based on the descriptions you're giving what you are doing and what you have/haven't tried of what I've suggested.

chelahmy commented 1 month ago

@gbj thanks for your help. I'm very clear now it has nothing to do with this template. I will create a new issue in the cargo-leptos repo.

chelahmy commented 1 month ago

I did set <Routes base="/v2"> but obviously ssr didn't pick it up. The browser threw errors due to missing '/v2' in the links:

GET https://mydomain.com/pkg/mlm.js [HTTP/1.1 404 Not Found 0ms]
GET https://mydomain.com/pkg/mlm.wasm [HTTP/1.1 404 Not Found 0ms]

In fact, I have to call the page with extra '/v2' https://mydomain.com/v2/v2.

So, this is a cargo-leptos issue.

benwis commented 1 month ago

This is to be expected. The js/css/wasm files are served by your server outside Leptos, they are not affected by base= on the Leptos Routet

On Fri, Sep 27, 2024, at 6:57 PM, Abdullah Daud wrote:

I did set <Routes base="/v2"> but obviously ssr didn't pick it up. The browser threw errors due to missing '/v2' in the links:

GET https://mydomain.com/pkg/mlm.js [HTTP/1.1 404 Not Found 0ms] GET https://mydomain.com/pkg/mlm.wasm [HTTP/1.1 404 Not Found 0ms] In fact, I have to call the page with extra '/v2' https://mydomain.com/v2/v2.

So, this is a cargo-leptos issue.

— Reply to this email directly, view it on GitHub https://github.com/leptos-rs/leptos/issues/3029#issuecomment-2380348660, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABVBTCPGNDRGSLOVKJ4OIZ3ZYYEIFAVCNFSM6AAAAABO5OLG2SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOBQGM2DQNRWGA. You are receiving this because you are subscribed to this thread.Message ID: @.***>