ryansolid / dom-expressions

A Fine-Grained Runtime for Performant DOM Rendering
MIT License
863 stars 125 forks source link

Closing tag omission in dom `transformElement()` is broken with table/tbody #228

Closed nicketson closed 1 year ago

nicketson commented 1 year ago

Here is a test file exhibiting the issue:

/**
 * @jest-environment jsdom
 */

describe("element count bug", () => {
  it("element count bug", () => {
    const foo = () => "foo";
    const div =
          <div>
            <div>
              <table>
                <tbody>
                </tbody>
              </table>
            </div>

            <div class={foo()}>
            </div>
          </div>;

    console.log(div);
  });
});

For the above JSX expression, transformElement() generates this template string "<div><div><table><tbody></div><div>". When this is passed to template() in the runtime, the node that it creates looks like this: <div><div><div></div><table><tbody></tbody></table></div></div>

It looks like when the browser parses the innerHTML of the HTMLTemplateElement, the <table> element forces the first child <div> to automatically close.

I've played around with HTMLTemplateElement a little bit and it looks like the template is processed correctly as long as you always close <table> and <tbody> tags.

Perhaps this toBeClosed mechanism could be generalized a bit more to always close table/tbody/thead/tfoot tags? https://github.com/ryansolid/dom-expressions/blob/7399a71d28e275ca86416d9f2be721a7a37c5b14/packages/babel-plugin-jsx-dom-expressions/src/dom/element.js#L120

ryansolid commented 1 year ago

Yeah.. for sure. Let me take a look and see the specific issue. There were some specific issues around anchors I thought I solved but realized that it does some crazy stuff (like auto wrap inline siblings).. I will see what the deal is with table.

ryansolid commented 1 year ago

Yeah like anchors, tables are just special. I assume the parser gets flagged to go into a mode until manually closed. And even if closed in the right location it causes other side effects on siblings until it walks back up to the parent. So both of those will be always closes.

I think what we are seeing is what tables do when they find an invalid item in them. It must see the future open div tag and try to pull it out of the table in front of itself even though autoclosing would prevent it from ever being inside of it.