hexops / vecty

Vecty lets you build responsive and dynamic web frontends in Go using WebAssembly, competing with modern web frameworks like React & VueJS.
BSD 3-Clause "New" or "Revised" License
2.79k stars 144 forks source link

Add support for adding external scripts to document. #300

Open ferealqq opened 2 years ago

ferealqq commented 2 years ago

This PR adds support for adding external scripts to the document.

Not sure if the way that I implemented 'attributes' to the AddScript function is the most convenient. Let me know what solution could fit better.

Created tests for AddScript function

soypat commented 2 years ago

Some observations:

  1. Function can fail if URL does not exist
  2. Script is not guaranteed to be loaded after function finishes

Here's an implementation that takes these into account: https://github.com/soypat/gwasm/blob/main/gwasm.go#L16

ferealqq commented 2 years ago

2. Script is not guaranteed to be loaded after function finishes

I commited a implementation that takes this into account. But I don't have sufficient knowledge of vecty to create a test for timeout exceeded scenario. Not sure how I could mock script has loaded event.

I manually tested it with these: https://gist.github.com/ferealqq/23ccb13aa93f551a63d245bf63919690

ferealqq commented 2 years ago
2. Script is not guaranteed to be loaded after function finishes

I had a second idea, what if we leave it up to the end user to decide what happens "onload". Because now AddScript function is kinda confusing.

In a timeout scenario AddScript will return a error but still the browser may load the script element. This can be circumvented by removing the script element from the head if the timeout limit is exceeded and/or we can clarify the functions functionality in a comment but both of these options seem kinda funky IMO.

AddScript could look something like this

// AddScript adds an external script to the document, does not guarantee that the script has been loaded. 
// If you want to guarantee that the script has been loaded use `onload`
func AddScript(url string, attributes map[string]interface{}, onload func(jsObject, []jsObject) interface{}) {
soypat commented 2 years ago

In Go it's not quite common to use "onX" callbacks. This kind of function makes control of user applications harder. The way people usually go about dealing with long lasting functions is just have them block and let the user decide if they want to run them asynchronously like so:

go func() {
    AddScript("url.com", nil)
    onload()
}()

This practice is best summarized as: Let users decide if they want concurrent programs or not. Don't use goroutines in user facing code if it can be easily circumvented.

That said, I'm not sure what @slimsag has to say about if vecty is the correct place for AddScript. In any case your changes are welcome over at gwasm if it comes to that.

ferealqq commented 2 years ago

That said, I'm not sure what @slimsag has to say about if vecty is the correct place for AddScript. In any case your changes are welcome over at gwasm if it comes to that.

True, it seems like this function is hard to implement in a way that it takes into account all of the factors mentioned. Which is unfortunate because function like AddScript could be useful in many scenarios when building a web application.

I'd love to find a way to implement this function inside vecty but I totally understand if this ain't the right place.