Open dzonerzy opened 1 year ago
If you're happy to spend time making a PoC then I'm happy to spend time looking at how we can integrate it
Also go-app support out of the box static site generation, so building a template could be actually easier, imo the best way is still adding full support, I'll try to make a poc and ping you back.
I'm stuck on an issue which seems like I can't figure out how to solve, when building go-app application a wasm file is created (creation of this file could be handled by npm, right now i'm using go generate), anyway mimetype for wasm seems to be application/vnd.microsoft.portable-executable I tried to create the following middleware but content-type won't change:
/*
* go-app-poc
* To use with linux change the following lines:
* //go:generate GOOS=js GOARCH=wasm go build -o frontend/src/web/app.wasm -ldflags=-w -ldflags=-s ./app
*/
//go:generate cmd /c set GOOS=js
//go:generate cmd /c set GOARCH=wasm
//go:generate go build -o frontend/src/web/app.wasm -ldflags=-w -ldflags=-s ./app
//go:generate go run ./app
package main
import (
"embed"
"net/http"
"github.com/wailsapp/wails/v2"
"github.com/wailsapp/wails/v2/pkg/options"
"github.com/wailsapp/wails/v2/pkg/options/assetserver"
)
//go:embed all:frontend/src
var assets embed.FS
func mimeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// if url is /web/app.wasm, set the mime type to application/wasm
if r.URL.Path == "/web/app.wasm" {
w.Header().Set("Content-Type", "application/wasm")
}
next.ServeHTTP(w, r)
})
}
func main() {
// Create an instance of the app structure
WailsApp := NewApp()
// Create application with options
err := wails.Run(&options.App{
Title: "go-app-poc",
Width: 1024,
Height: 768,
AssetServer: &assetserver.Options{
Assets: assets,
Middleware: assetserver.ChainMiddleware(
mimeMiddleware,
),
},
BackgroundColour: &options.RGBA{R: 27, G: 38, B: 54, A: 1},
OnStartup: WailsApp.startup,
Bind: []interface{}{
WailsApp,
},
})
if err != nil {
println("Error:", err.Error())
}
}
Below the response headers
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: no-cache
Content-Length: 7604224
Content-Type: application/vnd.microsoft.portable-executable
Last-Modified: Mon, 09 Jan 2023 12:54:14 GMT
Date: Mon, 09 Jan 2023 13:01:09 GMT
Note that go-app check app.wasm mimetype before loading it
Got it working, it was my issue the wasm wasn't generated correctly, below the poc repo:
https://github.com/dzonerzy/go-app-poc
Right now I use go generate to build wasm on the fly but that could be done by the watcher itself when rebuild the application. Also I'm sure there are better way to interop with wails runtime , in the poc I call the greet function.
Let me know what you think and I'll be more than happy to help you with that.
Regards, dzonerzy
Any progress on this topic?
I like the idea to use Go as the only programming language.
@leaanthony do you need more info on the topic? I can try to implement that by myself if you prefer.
Hey 👋 that sounds great! This flew under the radar a bit.
Almost finished the new template. It needs some polishing, and I must find a better way to handle bindings, but it's still a starting point; I already integrated it inside Wails cli.
Right now I use some hack to make it works fine with Vite server for dev purposes, but I'm sure this can be done way better.
//go:generate go run .
//go:generate go run generate_wasm.go
//go:generate npx tailwindcss-cli@latest build -i main.css -o style.css
package main
import "github.com/maxence-charriere/go-app/v9/pkg/app"
type hello struct {
app.Compo
name string
greet string
}
func (h *hello) Render() app.UI {
return app.Div().ID("App").Body(
app.Img().Src("/images/logo-universal.png").Alt("logo").ID("logo"),
app.Div().ID("resut").Class("result").Body(
app.If(h.name != "", app.Text(h.greet)),
),
app.Div().ID("input").Class("input-box").Body(
app.Input().ID("name").Class("input text-black").AutoComplete(false).
Name("input").Type("text").OnChange(h.ValueTo(&h.name)),
app.Button().Class("btn").OnClick(h.Greet).Text("Greete"),
),
)
}
func (h *hello) Greet(ctx app.Context, e app.Event) {
res := app.Window().Get("go").Get("main").Get("App").Call("Greet", h.name)
res.Then(func(v app.Value) {
h.greet = v.String()
h.Update()
})
}
func main() {
app.Route("/", &hello{})
app.RunWhenOnBrowser()
h := &app.Handler{
Title: "Hello",
Styles: []string{
"style.css?direct",
"app.css?direct",
},
Description: "A progressive web app written in Go.",
}
app.GenerateStaticWebsite(".", h)
}
Forgive the extra 'e' in Greet !
This is incredible! 👏 If the frontend is compiled wasm, is there a need for vite?
I added vite with a custom configuration and some plugins, in that way it's possible to have an immediate feedback when something change, right now when a go file is modified there's a vite hook which will generate the static files and and will build the wasm.
Ah I see. Thanks for the clarification
What do you think is the best way to include such a template? Do you prefer having it as an external template or built-in inside the cli? I see many people have external repos with their templates. Also, regarding the binding at the moment, the wails binding is unused since the vite server is only building sources from frontend/src/. Still, I would like to know if it is possible to generate golang bindings together with js + ts bindings. This way, adding a go.mod files inside the frontend directory is enough to make them importable from go-app.
External template for now as the maintainers aren't across go-app (yet!). Regarding bindings, I'm not 💯 on what you mean. It's not possible to call any new Go bindings without recompiling the app.
I think it's way better if you could look at the repo https://github.com/dzonerzy/wails-go-app-v2 right now, there are a few things I don't like. Maybe you could suggest better ways to handle such cases:
1 - The frontend distribution folder is and must be outside the frontend folder 2 - There's no direct way to use the wails-generated binding in Go since Vite removes them during the bundling operation due to tree shake (they are used in Go, not in JS or TS) 3 - Vite uses a lot of custom plugins to copy needed files for distribution. Is there a better way to handle and bundle WASM files?
Now let me explain why I was forced to make some of the above choices:
1 - Golang can't embed a file/folder residing in a different module (since the frontend folder is a go module itself due to the go-app) 2 - I haven't found a solution to this issue. I was also thinking about making wails-generating go-app binding in Golang; that could be handy since they are already inside the frontend module so that the go-app could import them. 3 - I could not find a better solution than using a custom site hook to copy static files (WASM, js) to the distribution folder.
Any feedback is appreciated, Thanks!
Is your feature request related to a problem? Please describe.
Wails is a great product which allow building richful UI via web tech, I was thinking of a way to allow someone who's not too familiar with web technologies to build such rich UI.
Describe the solution you'd like
I think supporting https://github.com/maxence-charriere/go-app could be a plus, it allow build PWA using pure go declarative syntax
Describe alternatives you've considered
No response
Additional context
As long as I know go-app make use of wasm to build UI, being wasm itself a web technology I don't think should be too hard to implement, instead of running an assets server wails could give users the option to run their own defined server which would display go-app application.