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

During SSR hydrate() resets the html body #2822

Closed
Neo-Ciber94 opened this issue Aug 12, 2022 · 4 comments
Closed

During SSR hydrate() resets the html body #2822

Neo-Ciber94 opened this issue Aug 12, 2022 · 4 comments

Comments

@Neo-Ciber94
Copy link

Neo-Ciber94 commented Aug 12, 2022

Problem

Steps To Reproduce

  1. Using the Simple SSR example
  2. Changing the simple_ssr_server render function to:
async fn render(
    index_html_before: String,
    index_html_after: String,
) -> Box<dyn Stream<Item = Result<Bytes, BoxedError>> + Send> {
    let renderer = yew::ServerRenderer::<App>::new();

    Box::new(
        stream::once(async move { index_html_before })
            .chain(renderer.render_stream().await)
            .chain(stream::once(async move {
                "<script id=\"MY_SCRIPT\">console.log('Hello World!')</script>".to_owned()
            }))
            .chain(stream::once(async move { index_html_after }))
            .map(|m| Result::<_, BoxedError>::Ok(m.into())),
    )
}
  1. Go to localhost and open the Developer Tools

The console prints the message but the script do not exists in the html but was sent from the server

Screenshots
image

HTML

image

Source

image

image

Expected behavior
To have all the content added to the body in the client side

@futursolo
Copy link
Member

futursolo commented Aug 12, 2022

This is expected. Yew expects the container to only contain elements to be hydrated / rendered.

To avoid this, You can render Yew application to a div container like React.

@Neo-Ciber94
Copy link
Author

@futursolo

As you mentioned updating the code to:

async fn render(
    index_html_before: String,
    index_html_after: String,
) -> Box<dyn Stream<Item = Result<Bytes, BoxedError>> + Send> {
    let renderer = yew::ServerRenderer::<App>::new();

    Box::new(
        stream::once(async move { index_html_before })
            .chain(stream::once(async { "<div id=\"CONTAINER\">".to_owned() }))
            .chain(renderer.render_stream().await)
            .chain(stream::once(async { "</div>".to_owned() }))
            .chain(stream::once(async {
                "<script id=\"MY_SCRIPT\">console.log('Hello World!')</script>".to_owned()
            }))
            .chain(stream::once(async move { index_html_after }))
            .map(|m| Result::<_, BoxedError>::Ok(m.into())),
    )
}

Gave me this html:

image

And also this error

image

And this is what was sent from the server:

image

Formatted:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Yew SSR Example</title>

    <script type="module">
      import init from "/simple_ssr_hydrate-219bb34af1aee7b6.js";
      init("/simple_ssr_hydrate-219bb34af1aee7b6_bg.wasm");
    </script>

    <link
      rel="preload"
      href="/simple_ssr_hydrate-219bb34af1aee7b6_bg.wasm"
      as="fetch"
      type="application/wasm"
      crossorigin=""
    />
    <link rel="modulepreload" href="/simple_ssr_hydrate-219bb34af1aee7b6.js" />
  </head>
  <body>
    <div id="CONTAINER">
      <!--<[simple_ssr::App]>--><!--<[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--<[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--<?>--><!--<[simple_ssr::Content]>-->
      <div>Random UUID: 81b54d79-b256-4fb0-aa12-44e024f8ff5f</div>
      <script type="application/x-yew-comp-state">
        ARAAAAAAAAAAgbVNebJWT7CqEkTgJPj/XwE=
      </script>
      <!--</[simple_ssr::Content]>--><!--</?>--><!--</[yew::suspense::component::feat_csr_ssr::BaseSuspense]>--><!--</[yew::suspense::component::feat_csr_ssr::Suspense]>--><!--</[simple_ssr::App]>-->
    </div>
    <script id="MY_SCRIPT">
      console.log("Hello World!");
    </script>
  </body>
</html>

@futursolo
Copy link
Member

The container element needs to be specified on the client-side renderer or it would default to document.body.

See:

https://api.yew.rs/next/yew/struct.Renderer.html#method.with_root

https://github.com/yewstack/yew/blob/master/examples/two_apps/src/main.rs#L72

@Neo-Ciber94
Copy link
Author

Thanks, after updating the simple_ssr_hydrate to:

use simple_ssr::App;

fn main() {
    #[cfg(target_arch = "wasm32")]
    wasm_logger::init(wasm_logger::Config::new(log::Level::Trace));

    let root = web_sys::window()
        .expect("Expected window")
        .document()
        .expect("Expected document")
        .query_selector("#CONTAINER")
        .expect("Failed to query element")
        .expect("Failed to find root element");

    yew::Renderer::<App>::with_root(root).hydrate();
}
[dependencies]
web-sys = "0.3.59"
# other deps...

The code run without errors

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants