-
-
Notifications
You must be signed in to change notification settings - Fork 304
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
Enhancements needed for using templ inside a Wasm environment #1001
Comments
Thanks for compiling your research into such a well written report. I'll take a read through, but want to give it the proper thinking time rather than rushing it, so won't be in the next couple of days. |
I'm struggling to understand this, probably because I've never tried to run Go in Web Assembly. I think that some examples would be useful! FWIW, there's a WASM based templ playground at https://play.templ.guide/ You can see the code at https://github.com/templ-go/playground Not sure if that helps... |
I've also stumbled upon this, i'll make another example: templ MyExample(user string, show bool) {
<script>
function writeUserName(el,name,show){
if (!show){
return;
}
el.innerHTML=name
}
</script>
<div
onClick="writeUserName(this,'test',true)"
// I'd like to inject the values directly
// onClick="writeUserName(this,{user},{show})"
style="width: 200px; height: 200px; background-color: #BEBEBE; color: black;"
>
placeholder
</div>
} A workaround could be: templ MyExample(user string, show bool) {
<script>
function proxy(el) {
const user = el.getAttribute('arg-user');
const show = el.getAttribute('arg-show') !== null;
writeUserName(el, user, show);
}
function writeUserName(el, name, show) {
if (!show) {
return;
}
el.innerHTML = name;
}
</script>
<div
onClick="proxy(this)"
arg-user={ user }
arg-show?={ show }
style="
width: 200px;
height: 200px;
background-color: #bebebe;
color: black;
"
>
placeholder
</div>
} To me this is not very intuitive and pretty distant from the general approach: "open a pair of curly brackets and dump some text into some html" Anyways, thanks for your work and please correct me if i'm wrong 😃 |
Thanks for the input I will try out the suggestions. |
Hello, a while back I promised to check back with findings on trying out templ inside a Wasm environment. So here are my findings:
Preface
Use Cases
Most of us coming from Go have the notion of Go as a backend language but when using Wasm things are totally different.
We now have a backend and platform agnostic frontend language and as such we can in theory use Go as a type safe compiled language in all browser environments with a few considerations. So the most viable use cases are as a web frontend for a fully fledged computer application, since in a localhost environment bundle sizes of 10MB+ do not matter. Also if your Go Wasm Application brings something powerful to the table you might get away with a load screen of a few seconds.
Examples
So I mentioned Wasm being agnostic of the backend means that you can use it inside a QT web view, Wails, possibly even Tauri or Electron if you wanted since with the net/http package and encoding/json you can communicate with all backends amicably. This opens up a wide array of possibilities, since the only real integration with the backend that your Wasm frontend needs is the same definition of the data model.
Workflow
While experimenting I used wails as a backend but found that while developing your frontend this is not the best approach since you don't want the extra overhead on the turnaround times that wails introduces, but simply using vite or any other capable development server is preferable, since the only thing we need is something that will give us access to our assets and data.
Problems
Event Handling
In wasm you basically have two choices for event handling:
templ
Assumptions
in templ it is assumed that the html is created by the server which means that all the scripts that we create and special constructs like the script directive in templ templates are correctly evaluated and executed.
Reality
Component wide the html gets delivered in a string builder and then set to the components html element with a snippet like this:
This way the containing script will not be evaluated which renders most JS examples in templ.guide useless.
So the only way to make it work is by applying the script separately like so:
Issue
I have not found a way to construct a javascript call dynamically like
The quotation marks keep the variable from being evaluated and single quotes don't work either. I could be wrong but I don't see any way how to dynamically create parameters to give context to an event besides looking for custom attributes in the event target element.
If that is by design and intended forgive my ignorance but since JS conversions are costly I thought a string based approach would be much more practical especially when you consider that the receiver might be a fantastic javascript library that does not know anything about your custom data attributes.
Build Tags
To be able to use syscall/js package one has to specify build tags like so.
//go:build js && wasm
In a wasm environment it is totally acceptable and even a crucial feature to use other go files in the same package space as the generated template files to host utility functions and generally not pollute the template with lengthy code.
But this is only possible when they both share the same build tags also imports won't work if they don't share compatible build tags.
So when generating the go file build tags must either must be respected or if that is a problem at least there should be a command line flag like
that prepends the build tag separated with a newline from the "Do not edit" comment.
tldr;
Go, traditionally a backend language, takes on a new role in the WASM environment. It becomes a platform-agnostic frontend language capable of powering rich web applications. This shift opens possibilities for using Go in various contexts, including:
Development Workflow
While frameworks like Wails offer integrated development, a simpler setup with tools like
vite
can be more efficient for frontend development. This approach focuses on rapid iteration and asset management.Dynamic JavaScript Calls
Constructing dynamic JavaScript calls with
templ
is problematic due to quotation mark escaping issues. This limits the ability to pass context to event handlers, potentially hindering integration with JavaScript libraries.Finding a way to manage javascript in a centralized way would be beneficial for everyone using templ since that would solve innerHTML issues and improve JS Code organization. I will not propose a solution since this is out of scope of this writeup.
Build Tags
Using the
syscall/js
package requires specific build tags://go:build js && wasm
This poses challenges when:
Proposed Solution
Introduce a command-line flag to templ for specifying build tags in generated files:
This would prepend the specified build tag to the generated Go files, ensuring compatibility and code organization.
Conclusion
Addressing these issues will enable templ's usability in WASM environments, allow developers to leverage its strengths for building complex and interactive applications, with the added benefit of not having to deal with javascript focused build steps (node modules, dependency issues)
P.S. Apologies you were right about the watch flag causing the problems in my last issue :)
The text was updated successfully, but these errors were encountered: