Open norunners opened 6 years ago
@norunners thank you for reporting this. I can't promise that I will be able to fix it anytime soon as vdom has not been a priority for me for a long time now. Still, I may take a look if I have time.
If you want to do more digging yourself, I would start by taking a closer look at the findInDom
function as I think the issue is originating there.
Hey @norunners, I think I discovered a workaround, though it doesn't entirely fix the issue. I was able to get it to work by changing index.html
from this:
<div id="app">
</div>
to this:
<div id="app"></div>
I'm probably going to do a little more digging, but that should help get you up and running at least.
I've discovered a little more about the root cause, but haven't developed a proper fix yet. It comes down to the way that HTML nodes are represented in the DOM, and some assumptions that are apparently made by vdom's diffing algorithm.
Ultimately, the issue is that in the following two examples, the app
div has two different child node counts:
<!-- app has only one child: the paragraph element -->
<div id="app"><p>Hello!</p></div>
<!-- app has two children: a text node, and the paragraph element -->
<div id="app"> <p>Hello!</p></div>
vdom uses index lists to traverse from a root element to the one that needs to be modified, and in both these cases, it attempts to navigate to the Hello!
text node using the list [0 0]
. In the second case, it stumbles upon the text node, which has no children and therefore causes a panic.
It looks like the root cause is a fundamental difference in how XML and HTML are parsed. Currently, vdom uses an XML parser tuned with some recommended settings for parsing (most) HTML. However, if you look at the documentation for "encoding/xml".Unmarshal, it points out that whitespace is always trimmed and ignored. This is a subtle but important distinction between how the parser works and how the underlying dom package works, which treats whitespace as significant.
The correct fix for this is to update vdom to use an HTML parser instead of XML. The good news is that Go has one that is officially maintained, albeit not technically in the standard library. The bad news is that it's quite a large change to switch out the underlying parser.
Investigating this has also given me the opportunity to re-evaluate vdom's API, and propose a way to potentially make it simpler. I started developing a proof-of-concept in a new repository: https://github.com/dradtke/vdom2. It's extremely simple and would need a lot more work, but does work for norunner's original use-case (see that repository's example
folder), and avoids the bug that originally prompted this issue.
Thank you for investigating this and providing detailed explanations. I’m going to try and use an html minifier before parsing as a short term fix. I’ll check out vdom2 and stay tuned in the future. Also, does it make sense to have a patch for event listeners? Maybe this need not be a concern of a virtue dom.
Nice work @dradtke what do you think the vdom implementation of vecty? https://github.com/gopherjs/vecty/blob/master/dom.go
I'm also creating a vdom framework like vecty here, https://github.com/krab-dev/exo/blob/master/html.go
Hello, I've encountered an error while calling
vdom.Patch
on the second render, the first render is successful. Am I missing something critical in this example or is this a bug?Error:
Error: runtime error: index out of range
Source:
main.go
Source:
index.html
First render: