-
-
Notifications
You must be signed in to change notification settings - Fork 373
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
Generated wasm too large #534
Comments
You can serve it gzipped. |
Yes. Still it will be around 3 MB. I will experiment with |
If you dont use http you can separate client code in another package. It the http package that add a lot. |
Thanks for the suggestion. I have been trying to build with tinygo but it seems to have some issues. I have added the issue tinygo-org/tinygo#1886. |
Tinygo is not supported by this package for now. |
FWIW, there has been some progress on the tinygo side of this, e.g.: |
Just make two files that contains "serve" function. In GOOS=js target this function will be empty. Without it : 12 Mb Then use brotli to reduce it again: Result: 985 Kb |
I am experimenting with go-app right now. To get the sizes down I made two targets for the HTTP server and one is a stub. In addition, I experimenting in using the chi router and with that, I have a compression middleware for the wasm. This brings the size to 1.3 MB (from >16 MB) and lets me add the backend code using chi. I also experiment with "live reloading" (through a javascript HEAD checking and using reflex for recompilation). This is a bit rough about the edges but I am actually pretty happy with how everything works so far. You may want to look at https://github.com/oderwat/go-guess-the-number-app (this is not meant to be public for real, but I thought I want to share this as example and maybe get comments) |
@oderwat You are right. We might end up needing to separate the http package and still use Tinygo to achieve js world bundle sizes. Thanks for the example. Splitting into two files doesn't seem to reduce the size though. Can you elaborate on your results? |
13.3 MB compressed? My testing (a lot of stuff) app has currently 13.8 MB which ends up as 3.2 MB with on-the-fly compression middleware. I also use my #631 PR to show people a loading indicator, which makes its loading time "more accepted" as it shows the progress to the user. But I hope that we get TinyGo to work. Sadly I just came from my vacation and my day job has different priorities at the moment. |
Hey not a problem. I don't see any difference in the wasm size after splitting into two files actually it's 13.3 MB not compressed and around 3 MB when compressed so no improvement over the original inclusion of the http package. I think when building the wasm the http package is still included. In the end I think we will need both this technique and Tinygo for best results. |
Well, I use HTTP clients in the frontend anyways. But there are other packages that could be used (maybe https://github.com/golangee/wasm-net). But I did not have time to try it yet. |
That is as a wasm server, not an HTTP client library to use in the frontend? The Server is fine in go-app as it is just the server binary where size matters less. |
Sure. But when you access APIs from the frontend you need to use one or more HTTP clients in the code. |
Yes, my misconception. So we can't save size on that front in an easy straight forward way. It remains a mystery though why the tinygo produced files are still big. Also the http client in react is 2.5 KB in Go it's 7 MB, quite a big difference. Can we find an alternative tiny http client let's say developed for embedded devices? |
Never mind: https://github.com/golangee/wasm-net is not what I meant. This also includes |
A gRPC client? We already have an example of using that in go-app: #447 |
It is about "net/http" in the frontend part and you can not just use gRPC to access an HTTP API. I am not talking only about the client/server communication of the app itself.
No, we don't? It does not change the WASM size at all that you use net/http for the server-side. |
I meant trying to use gRPC API instead of HTTP API in order to avoid including the net/http package. But we still need something to serve the wasm file tothe browser. I think it's precisely the net/http package that adds size, actually more than half of it. |
And btw. gRPC uses HTTP/2. I would rather use something like https://github.com/twitchtv/twirp |
Yeah I am not speculating about that, anything as an alternative to a smaller final size. |
It was stated previously that the net/http package adds 7 MB. |
You can not use gRPC for an HTTP API. We need to access a lot of different APIs and not all of them are made by us. The key to a smaller size will be TinyGo until the Go compiler gets optimized for WASM. |
Please read the pull request discussion. Tinygo successfully compiled but the final size was 6.3 MB. So Tinygo doesn't solve the problem with size. It's the net/http package that mainly contributes to the big wasm size. |
And I say you can probably use the browsers XMLHttpRequest() for this and don't need |
How are we going to serve the wasm file to the browser without http.ListenAndServe? |
I hope @maxence-charriere can clarify the basics here. |
@mar1n3r0 you simply build two times. One for the WASM not containing the server and one for the server itself (which simply uses net/http). |
They are the same package how do you split them? In your example the final size remains unchanged from before the split. |
main.go func main() {
// Frontend routing
app.RouteWithRegexp("/.*", &appControl{})
// this concludes the part which goes into the front-end
app.RunWhenOnBrowser()
// this will depend on the target (wasm or not wasm) and
// it starts the servers if it is not the wasm target.
AppServer()
} wasmstub.go // Our empty version of the httpServer for usage with the wasm target
// this way we will not include any of the related code
//go:build wasm
package main
func AppServer() {
} server.go // Our empty version of the httpServer for usage with the wasm target
// this way we will not include any of the related code
//go:build !wasm
package main
import (
....
)
func AppServer() {
// the actuall server code
...... |
If that uses my "template" replacement it may need |
But I only want to use TinyGo for the WASM part and that hardly ever needs to use "SetEnv" as (afaik) there is nothing like "env variables" in WASM. I didn't had time what this "SetEnv" actually is used for. The error you get is also template-related. |
This is the original go-app code. Haven't touched anything there. |
How can you compile using TinyGo without a replacement for You need #680 or something similar. |
I used your hard-coding from the PR and also commented this: `func (h *Handler) makeAppJS() []byte {
}` So yeah it's normal that it's not working since the env variables are set here by SetEnv. |
Yeah because {{.Env }} was not replaced by the env variable which is not set. If i remove the comments it starts working so it's certainly there. |
And please don't comment out:
It is just os.SetEnv() which does not work (and looks useless to me. I don't understand what this is good for when the target is WASM. But maybe it is compiled twice. I don't know (yet) |
|
{{.Env}} is not replaced by an Env variable but with the value of the map which is defined about. |
That's that for now until SetEnv is implemented in TinyGo. |
The IsServer part should never run when wasm is the target so maybe put this in an extra file similar to the server code itself, so it will not include the call at all. |
BTW: My main testing app still does not compile with TinyGo (after getting rid of the os.SetEnv()) because of |
{{.Env }} is unchanged in my test so not taken from your template. I have no idea where the xml error comes from maybe send a full trace of the running code or a repo with it. |
Here's a lighter weight http client for wasm : https://github.com/marwan-at-work/wasm-fetch |
@mlctrez yep this is exactly the one I had in mind |
A common pattern is to have a server configurable from environment variables. Things like api endpoint can be configured and be automatically relayed to a client. |
I also made a try for tinygo support. Here is the code: #682 I was able to compile but look like there is still some issues to figure out. note that this is pure hacking and is far from being stable. |
@maxence-charriere Please keep the Tinygo issue open as it is quite close to being completed. |
@mar1n3r0 i don’t give up. I got that a lot of you folks want this to happen. |
If the compile times are longer but the result is (much) smaller it may just be good enough to use it for deployment. I also experienced quite long compile times while working on WASM "plugins" with TinyGo (and I am not sure if I wanna trust it to create stable code). |
@oderwat same here but I don't consider 1 min compile time to be a show stopper if the benefit is 50% + reduced binary size. To be honest I also expected 10 times reduction so a bit disappointed. |
Some important links / milestones, to save time the next person trying to read through the whole thread --
We might not be able to achieve the best in one shot, IMHO, even things half done is better than the current situation, as my Original app.wasm size is 14 MB, |
Hi @mar1n3r0, I'm reviving this thread a little bit, since you mention tinygo is working, but I'm still having a link-time issue with
how exactly did you manage to get past this one ? cheers, |
Sadly not there yet, see: #682 |
well that's too bad 😢 in the meantime, did you try brotli or zstd compression instead of gzip ? |
Nope, gzip only so far. |
That cannot really be handled on go-app side. |
Thank you for your contribution. This looks pretty awesome to work with. I just started playing around with it.
I started with minimal example:
Generated wasm with:
But the generated wasm is a whooping 11.5 MB. Any suggestion to reduce the file size?
Go version:
1.16.4
The text was updated successfully, but these errors were encountered: