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

Tinygo is just one package away #679

Open
mar1n3r0 opened this issue Jan 9, 2022 · 29 comments
Open

Tinygo is just one package away #679

mar1n3r0 opened this issue Jan 9, 2022 · 29 comments

Comments

@mar1n3r0
Copy link

mar1n3r0 commented Jan 9, 2022

Good news, I know that a lot of people are waiting for this.

The net/http and encoding/json packages are now implemented in tinygo.

The only package left for it to compile successfully is text/template:
https://tinygo.org/docs/reference/lang-support/stdlib/#texttemplate
tinygo-org/tinygo#752

text/template relies heavily on reflect which is one of tinygo's weak points. You might be better off looking for a code-generation template library if possible.
?

@maxence-charriere Could this be an easy to bypass stumble block?

Maybe this:
https://github.com/valyala/fasttemplate

Let's keep that issue open and track progress here.

@oderwat
Copy link
Contributor

oderwat commented Jan 9, 2022

Very good indeed! I made a quick replacement for the usage of text/template (see: #680)

Compilation now fails with a missing function in os. I did not follow up changing more code yet.

>$ tinygo build -o tiny.wasm -target wasm cmd/app/main.go
# github.com/maxence-charriere/go-app/v9/pkg/app
../go-app/pkg/app/http.go:334:16: Setenv not declared by package os

@dkegel-fastly
Copy link

dkegel-fastly commented Jan 22, 2022

The dev branch of tinygo has supported os.Setenv for about a month now.

Try building the dev branch from source... or wait a week or so for the 0.22 release.

@oderwat
Copy link
Contributor

oderwat commented Jan 22, 2022

@dkegel-fastly os.Setenv is just a minor problem. The missing timers is much more serious, see #682

The title of this issue is misleading, as it will be always "one package" away till all of them are supported :-)

@dkegel-fastly
Copy link

Thanks. That's tinygo-org/tinygo#1037

@justinfx
Copy link

Tiny-go says they just released the support for timers.

@mar1n3r0
Copy link
Author

mar1n3r0 commented Oct 9, 2022

Depends on WASI support in Go. See: tinygo-org/tinygo#2910

@gedw99
Copy link

gedw99 commented May 3, 2024

Hey all

I gave github.com/maxence-charriere/go-app/v10 a try today and the only bug is

# github.com/maxence-charriere/go-app/v10/pkg/app
../../../../../../../../../../../pkg/mod/github.com/maxence-charriere/go-app/[email protected]/pkg/app/node.go:784:13: v.Equal undefined (type reflect.Value has no field or method Equal)
../../../../../../../../../../../pkg/mod/github.com/maxence-charriere/go-app/[email protected]/pkg/app/node.go:789:14: v.Equal undefined (type reflect.Value has no field or method Equal)

from https://github.com/mlctrez/mlctrez.github.io/issues/1 where the test code is.

@oderwat
Copy link
Contributor

oderwat commented Aug 23, 2024

I just saw the headline of this issued and can't resist commenting that this is like: Fusion, General AI and Half-Life 3. It may also end up like "Duke Nukem Forever", which was not very pleasing.

I gave github.com/maxence-charriere/go-app/v10 a try today and the only bug is

Well, this is not the only problem (not a bug at all) but just the current "first" problem.

As far as I remember it was not even bringing the expected gains when it was getting compiled with TinyGo in a "cheated" fashion. So it may not even worth the effort.

To not only leave a basically useless comment, I want to point out some things:

  • We had some success to use wasm-opt from https://github.com/WebAssembly/binaryen to reduce WASM file sizes for the original Go compiler results. This was not battle tested through.
  • Even when you separate frontend code from backend code, you should check on the included packages. The Go compiler has a tendency to include stuff you do not expect. We once had megabytes wasted, because it was including a CLI argument parsing library that was used in another package and somehow (I think because of a global variable they use) stuck in the WASM result.
  • I believe it is better to utilize web workers (!= service workers) to load/swap WASM modules when needed and gain real parallel processing that way. Such modules can be compiled with TinyGo. This even works without having a web worker. But you are very limited in what that can do. Still can make sense for business logic that needs to run in the frontend.

Sorry for being off-topic. I just can't see how TinyGo can be used and wanted to share some experience we made in the topic of cutting down the size of the (main) WASM module.

@Skarlso
Copy link
Contributor

Skarlso commented Mar 4, 2025

@oderwat Hello. I would like to try and experiment again. I know you're saying the cheated version didn't affect much, but tiny go came a long way now and some of the linked issues in Go supporting WASI were also released and closed.

What do I need to do to built things using tiny-go? Is there some doc somewhere I could follow and play around with? ( Also tiny-go + wasm-opt might be interesting ).

@oderwat
Copy link
Contributor

oderwat commented Mar 4, 2025

@Skarlso You could check out #682

@Skarlso
Copy link
Contributor

Skarlso commented Mar 4, 2025

Thanks! I'll take a look!

@dkegel-fastly
Copy link

I see yesterday's tinygo 0.36 release fixed one of the previous blockers:
tinygo-org/tinygo@9a1cde4

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

Okay, I actually got it to work folks.

The build time increase is insane, I agree.. it's from around 10s to 53s. However, I don't care. The size gain is MASSIVE. From 25 to 5. And without even doing any wasm-opt.

I need some help getting this to run.

I run make gen and updated the wasm_exec.js location to point to tinygo's wasm_exec.js. However, when I say make run and build with tinygo, it's still using the old wasm_exec.js. And I don't understand why. :D

I cleared all the caches, and updated the wasm_exec.js inside docs/web as well. And it's still using the old wasm_exec.js.

I can see wasmExecJSGoCurrent does have the updated JS content...

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

Okay, it's this thing:

func wasmExecJS() string {
	version := strings.Split(runtime.Version(), ".")
	if len(version) < 2 {
		fmt.Println("NOPE")
		return wasmExecJSGoCurrent
	}

	fmt.Println("THIS IS HAPPENING")

	major, _ := strconv.Atoi(strings.TrimPrefix(version[0], "go"))
	minor, _ := strconv.Atoi(version[1])

	switch {
	case major == 1 && minor < 24:
		return wasmExecJSGo121

	case major == 1 && minor < 21:
		return wasmExecJSGo120

	default:
		return wasmExecJSGoCurrent
	}
}

Apparently, I need to do something to runtime.Version?

Okay, for now, I just made this return the wasm_exec.js. It is loading, however, I'm getting some JS errors which will be difficult to debug, because I have no idea about JS. :D

But the good news is that it's actually loading. :)

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

This is the error:

main-0174a80e:0x4132f Uncaught (in promise) RuntimeError: unreachable
    at main.runtime.runtimePanicAt (main-0174a80e:0x4132f)
    at main.runtime.nilPanic (main-0174a80e:0x4bb7)
    at main.interface:{Bool:func:{}{basic:bool},Call:func:{basic:string,slice:interface:{}}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},Delete:func:{basic:string}{},Equal:func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value}{basic:bool},Float:func:{}{basic:float64},Get:func:{basic:string}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},Index:func:{basic:int}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},InstanceOf:func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value}{basic:bool},Int:func:{}{basic:int},Invoke:func:{slice:interface:{}}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},IsNaN:func:{}{basic:bool},IsNull:func:{}{basic:bool},IsUndefined:func:{}{basic:bool},JSValue:func:{}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},Length:func:{}{basic:int},New:func:{slice:interface:{}}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},Set:func:{basic:string,interface:{}}{},SetIndex:func:{basic:int,interface:{}}{},String:func:{}{basic:string},Then:func:{func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value}{}}{},Truthy:func:{}{basic:bool},Type:func:{}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Type},github.com/maxence-charriere/go-app/v10/pkg/app.addEventListener:func:{basic:string,named:github.com/maxence-charriere/go-app/v10/pkg/app.Func,map:{basic:string,interface:{}}}{},github.com/maxence-charriere/go-app/v10/pkg/app.appendChild:func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Wrapper}{},github.com/maxence-charriere/go-app/v10/pkg/app.delAttr:func:{basic:string}{},github.com/maxence-charriere/go-app/v10/pkg/app.firstChild:func:{}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},github.com/maxence-charriere/go-app/v10/pkg/app.firstElementChild:func:{}{named:github.com/maxence-charriere/go-app/v10/pkg/app.Value},github.com/maxence-charriere/go-app/v10/pkg/app.getAttr:func:{basic:string}{basic:string},github.com/maxence-charriere/go-app/v10/pkg/app.removeChild:func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Wrapper}{},github.com/maxence-charriere/go-app/v10/pkg/app.removeEventListener:func:{basic:string,named:github.com/maxence-charriere/go-app/v10/pkg/app.Func}{},github.com/maxence-charriere/go-app/v10/pkg/app.replaceChild:func:{named:github.com/maxence-charriere/go-app/v10/pkg/app.Wrapper,named:github.com/maxence-charriere/go-app/v10/pkg/app.Wrapper}{},github.com/maxence-charriere/go-app/v10/pkg/app.setAttr:func:{basic:string,basic:string}{},github.com/maxence-charriere/go-app/v10/pkg/app.setInnerHTML:func:{basic:string}{},github.com/maxence-charriere/go-app/v10/pkg/app.setInnerText:func:{basic:string}{},github.com/maxence-charriere/go-app/v10/pkg/app.setNodeValue:func:{basic:string}{}}.appendChild$invoke (main-0174a80e:0x1e32b9)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)
    at main.(:7777/github.com/maxence-charriere/go-app/v10/pkg/app.nodeManager).Mount (wasm://wasm/main-0174a80e)

And this is how it looks like. :D

Image

So it almost loaded. :D I'm guessing some things will need to be updated in the gen maybe.

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

I've gotten some things to work, but there is some kind of problem where values are nil and then in the enginex.Start function all go routines are asleep and I'm getting an error. I'm still trying to figure out why.

@oderwat
Copy link
Contributor

oderwat commented Mar 5, 2025

Just a note: When I had one of our real production projects compiled with TinyGo, in the not working "cheated" version, it was not considerably smaller, even with me taking out complete packages that did not compile well. It also took many minutes to compile. I do not have the numbers anymore, but it was so devastating that I stopped working on it. I hope this works out better this time.

@mar1n3r0
Copy link
Author

mar1n3r0 commented Mar 5, 2025

The build time increase is insane, I agree.. it's from around 10s to 53s. However, I don't care. The size gain is MASSIVE. From 25 to 5. And without even doing any wasm-opt.

5x decrease in size sounds very promising.

@oderwat
Copy link
Contributor

oderwat commented Mar 5, 2025

@mar1n3r0 I had such results too, but only with quite simple examples and apps. This is why I said production projects. We made some pretty large applications that use Go-App in the last years. Key to smaller WASM was careful selection of packages.

In the end, a complex production ready app had more problems with memory consumption (you need to control the GC) on Apple devices than the WASM size itself.

We never had anybody complain about the installation (or update) time of the PWAs. You can install large PWAs if the client needs the applications. Just don't make them update it every day. :)

I was never sold on using Go-App for "websites". I think I wrote an issue or comment about having a build mode that is not creating the service worker. I think that could lead to a situation where you use Go-App as SPA and like a normal website where WASM size really matters.

If this ends well I am happy like everybody, but I would not invest time for that. In the end "size did not matter" for our business. ;-)

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

@oderwat I have the output of the documentation ( aka the website for go-app ).

	-rwxr-xr-x 1 skarlso staff 21M Mar  5 07:55 docs/web/app.wasm*
	...
	-rw-r--r-- 1 skarlso staff 5.9M Mar  5 07:56 docs/web/tiny.wasm

I think this is amazing... And it is working, I just don't understand Javascript and the Value section how it passes in stuff etc. There is a nil somewhere or the values aren't translated correctly at some point. It's almost there I feel. :D

@mar1n3r0
Copy link
Author

mar1n3r0 commented Mar 5, 2025

@oderwat I have the output of the documentation ( aka the website for go-app ).

	-rwxr-xr-x 1 skarlso staff 21M Mar  5 07:55 docs/web/app.wasm*
	...
	-rw-r--r-- 1 skarlso staff 5.9M Mar  5 07:56 docs/web/tiny.wasm

I think this is amazing... And it is working, I just don't understand Javascript and the Value section how it passes in stuff etc. There is a nil somewhere or the values aren't translated correctly at some point. It's almost there I feel. :D

Will give it a try when I have some more time.

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

@oderwat Understood. I understand if it's not a priority. There are always bigger fish to fry. :)

@oderwat
Copy link
Contributor

oderwat commented Mar 5, 2025

@Skarlso I know that you use the documentation page. This is by no means any close to one of our apps.

For example, out "flagship" application is uncompressed and without any other optimizations 21.8 MB in size. This get compressed to 4.9 MB on transfer. This is what the user needs to load. It consists of a full (offline capable) business software for industrial kitchen. It handles multi client and location order planning, ordering, tracking, inventory counting and storage location management for over 200,000 goods. Furthermore, it also deals with handling QR code usage and assignment, as also some basic statistics.

We use a NATS server cluster for communication between the app and the backend, where the state is stored in Jetstream. This means that the frontend works without the backend, which is actually more a synchronization and authentication client for multiple MSSQL databases that run the full-featured kitchen control software, that has stuff like recipes, meal planning and much more.

Clients are hospitals, rest homes, meals on wheels delivery services, universities, and organizations that control such facilities.

@Skarlso
Copy link
Contributor

Skarlso commented Mar 5, 2025

Nice. I wonder how I build that using tinygo since I need custom imports and stuff. I don't understand enough yet. Trying to compile my none trivial app I'm getting missing library errors.

@dkegel-fastly
Copy link

Tinygo builds a large app for us here at my daytime job, but we had to go about it very carefully. A large app with lots of dependencies that currently builds with regular go is likely to run into trouble.

Does a "hello, world" go-app work properly with tinygo 0.36 yet? If not, maybe file a bug report at github.com/tinygo-org/tinygo with how to reproduce.

@oderwat
Copy link
Contributor

oderwat commented Mar 5, 2025

I used TinyGo for integrated devices and wrote some proof of concept WASM modules with it that can be loaded "on the fly" from Go-App code. But with a PWA this is also a bit useless. The modules need to be in the cache and after loading them, you can't really unload it. In the end you can include that code into the main application and don't care with all the extra overhead. If you need really "more larger modules" I find it also much better to simply integrate that using an Iframe or create multiple applications. :)

@gedw99
Copy link

gedw99 commented Mar 5, 2025

That’s what I also do . Many WASM loaded at runtime as needed into web worker ..

@mlctrez
Copy link
Contributor

mlctrez commented Mar 6, 2025

Sharing this here in case anyone else is attempting to build go-app using tinygo.
There are some incompatibilities still with later versions of go and tinygo:

tinygo-org/tinygo#4777

@dkegel-fastly
Copy link

I heard the tinygo maintainers were planning another release this month, presumably that'll have the fix ( tinygo-org/tinygo#4784 )

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

No branches or pull requests

7 participants