maxence-charriere / go-app

A package to build progressive web apps with Go programming language and WebAssembly.
https://go-app.dev
MIT License
7.75k stars 354 forks source link

Some content double rendering in the browser #912

Closed jsgoecke closed 3 weeks ago

jsgoecke commented 6 months ago

I have everything working with the framework fine, except some of the content renders twice on the web page. I am not attempting to render twice, AFAIK, so thinking this could be related to something deeper in the framework and related libraries used. Has anyone seen this and/or have a recommendation?

oderwat commented 6 months ago

What do you mean with "render twice"? Is "Render()" called twice or are you nodes in the DOM rendered "twice" and how do you know that?

Edit: Actually I wonder if you mean that the delievered page gets updated in the frontend, which what Go-App is for. You don't use it for rendering stuff "server side" for being shown in the frontend. This is merely for visitors that do now start the go-app framework (like webscrapers).

jsgoecke commented 6 months ago

These are duplicates in the same render on the indexPage:

Screenshot 2023-12-11 at 3 39 04 PM

Here is my main.go:

package main

import (
    "log"
    "net/http"

    "github.com/maxence-charriere/go-app/v9/pkg/app"
)

// Log HTTP requests
func logRequest(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Printf("Received request: %s %s", r.Method, r.URL)
        next.ServeHTTP(w, r)
    })
}

// The main function is the entry point where the app is configured and started.
// It is executed in 2 different environments: A client (the web browser) and a
// server.
func main() {
    // The first thing to do is to associate the hello component with a path.
    //
    // This is done by calling the Route() function,  which tells go-app what
    // component to display for a given path, on both client and server-side.
    app.Route("/", &indexPage{})
    app.Route("/about", &aboutPage{})
    app.Route("/contact", &contactPage{})

    // Once the routes set up, the next thing to do is to either launch the app
    // or the server that serves the app.
    //
    // When executed on the client-side, the RunWhenOnBrowser() function
    // launches the app,  starting a loop that listens for app events and
    // executes client instructions. Since it is a blocking call, the code below
    // it will never be executed.
    //
    // When executed on the server-side, RunWhenOnBrowser() does nothing, which
    // lets room for server implementation without the need for precompiling
    // instructions.
    app.RunWhenOnBrowser()

    // Finally, launching the server that serves the app is done by using the Go
    // standard HTTP package.
    //
    // The Handler is an HTTP handler that serves the client and all its
    // required resources to make it work into a web browser. Here it is
    // configured to handle requests with a path that starts with "/".
    http.Handle("/", &app.Handler{
        Name:        "Thive PE",
        Description: "Thrive PE Website",
    })

    if err := http.ListenAndServe(":8000", nil); err != nil {
        log.Fatal(err)
    }
}
oderwat commented 6 months ago

It looks like you do something wrong in the component that is rendering this page. The main is okay as is.

jsgoecke commented 6 months ago

I simply can't see it, here is the indexPage.go.

package main

import "github.com/maxence-charriere/go-app/v9/pkg/app"

// indexPage is a component that displays a the index page. A component is a
// customizable, independent, and reusable UI element. It is created by
// embedding app.Compo into a struct.
type indexPage struct {
    app.Compo
}

func renderMenu() app.UI {
    return app.Div().Class("menu").
        Body(
            app.A().
                Href("/").
                Text("Home"),
            app.A().
                Href("/about").
                Text("About"),
            app.A().Href("/contact").
                Text("Contact"),
        )
}

// The Render method is where the component appearance is defined.
func (h *indexPage) Render() app.UI {
    return app.P().Body(
        app.Link().
            Rel("stylesheet").
            Href("/web/thrive-pe.css"),
        app.Img().Src("web/images/thrive-pe-logo.png").
            Height(100).
            Alt("Thrive PE Logo"),
        renderMenu(),
        app.Div().Class("parent").
            Body(
                app.Div().Class("left-square").Body(
                    app.Img().Src("web/images/spiral.png").
                        Class("spiralImage").
                        Alt("spiral"),
                ),
                app.Div().Class("right-square").Body(
                    app.H1().
                        Text("Proactive Risk Management").
                        Class("title"),
                    app.P().
                        Text("Thrive Private Equity fund is focused on the operational carveout of high-growth opportunities in healthcare, insurance, cyber, and other industries."),
                ),
            ),
    )
}
oderwat commented 6 months ago

Well, I do not immediatly see a problem there. Did you check what elements are getting created in the browser?

P.S.: Placing the <link> tag inside of the body is maybe not the best thing. You can add that to the raw HTML of app.Handler and don't forget to add all your assets to the app.Handler() too.

maxence-charriere commented 6 months ago

Are you on a stable branch?, it look like something i got while working on v10.

jsgoecke commented 6 months ago

I am on github.com/maxence-charriere/go-app/v9 v9.8.0 // indirect. So not on v10 or a non-stable branch AFAIK.

jsgoecke commented 6 months ago

@oderwat That is the weird part that I forgot to call out. While it is rendered in the browser twice, the HTML in the dev console shows only once instance and what should be the valid HTML.

oderwat commented 6 months ago

Did you try it without the css?

jsgoecke commented 6 months ago

I did try without CSS. When I commented out this line in main.go: "app.RunWhenOnBrowser()" it stopped double rendering and works fine.

oderwat commented 6 months ago

When I commented out this line in main.go: "app.RunWhenOnBrowser()" it stopped double rendering and works fine.

This can't be the solution. If that line is missing, there is no frontend, and it will only show the pre-render version of the page (AFAIK).

You do compile the executable and the WASM code separately, right?

Maybe you want to try out some other code to have some references:

https://github.com/metatexx/go-app-todo https://github.com/oderwat/go-nats-app https://github.com/oderwat/go-guess-the-number-app

P.S.: Have you tried to leave out the app.Link() part. This usually goes into HEAD of the page (using the RawHeaders of app.Handler)

jsgoecke commented 6 months ago

Yes, I did move that to the proper place and out of the body. And yeah, the whole point is to have the frontend load. Thank you for the links.