vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.95k stars 8.24k forks source link

Incorrect vite warning regarding nesting tr directly in table element #12088

Open tomtheisen opened 1 day ago

tomtheisen commented 1 day ago

Vue version

3.5.10

Link to minimal reproduction

https://play.vuejs.org/#eNp9kDELwjAQhf9KuVnqoJMUQcVBBxV1zFLrWatpEpKLFqT/3SSlrYN0CS/vexfe5QMLpeKXRZhBQlgqnhLOmYiihNILb6S/6Hkydkcg4xY51Y/ACMhkUtyKPH4YKdyLHx9nkMlSFRz1XlEhhWEwiwLxLOVcvrfBI21x1PrZHbPnH/9hKu8xOGg0qF/IoGOU6hypwevTDiunO1jKq+UuPQCPaCS3vmMTW1pxdbV/cqHtplRSUyHys1lXhMK0S/miPlmHPAP3rauB1fu6k3ga5pioof4CfnKCSA==

Steps to reproduce

Create a SFC with this content.

<template>
  <table>
    <tr></tr>
  </table>
</template>

Vite will issue a warning:

warning: \ cannot be child of \

, according to HTML specifications. This can cause hydration errors or potentially disrupt future functionality.

This warning is factually incorrect. The relevant spec says that a <table> may contain:

In this order: optionally a caption element, followed by zero or more colgroup elements, followed optionally by a thead element, followed by either zero or more tbody elements or one or more tr elements, followed optionally by a tfoot element, optionally intermixed with one or more script-supporting elements.

This is because htmlNesting.ts does not list tr as a valid child of table, despite the spec allowing it.

What is expected?

I expect no warning to be produced.

What is actually happening?

A warning is produced from vite:

warning: \

cannot be child of \
, according to HTML specifications. This can cause hydration errors or potentially disrupt future functionality.

System Info

+-- @vitejs/plugin-vue-jsx@3.1.0
+-- @vitejs/plugin-vue@5.0.4
+-- @vue/tsconfig@0.4.0
+-- vite@5.4.8
+-- vue-tsc@2.1.6
`-- vue@3.5.10
KazariEX commented 21 hours ago
const table = document.createElement('table');
table.innerHTML = '<tr></tr>';
console.log(table.innerHTML);
edison1105 commented 18 hours ago

https://html.spec.whatwg.org/multipage/tables.html#the-tr-element Maybe we should modify the warning message.

Justineo commented 15 hours ago

I’d suggest making the check more flexible, as it’s not very comprehensive at the moment.

tomtheisen commented 13 hours ago
const table = document.createElement('table');
table.innerHTML = '<tr></tr>';
console.log(table.innerHTML);

I don't think this is showing what you think it is showing.

This is a serialized DOM. In HTML, <tbody> is explicitly optional, by specification, as I've cited above.

KazariEX commented 13 hours ago

I don't think this is showing what you think it is showing.我不认为这显示了你认为它所显示的内容。

This is a serialized DOM. In HTML, <tbody> is explicitly optional, by specification, as I've cited above.这是一个序列化的 DOM。在 HTML 中, <tbody>根据规范是明确可选的,正如我上面引用的那样。

The directly generated <table><tr></tr></table> during SSR becomes <table><tbody><tr></tr></tbody></table> during CSR, as mentioned in the warning, resulting in hydration mismatch. This is what I want it to showing.

tomtheisen commented 13 hours ago

At a minimum the warning shouldn't claim that this is due to a spec. It seems this is constraint introduced by the implementation details of hydration. It could say something like this.

Despite being valid HTML, Vue SSR does not support direct nesting of <tr> within a <table>. Doing this can cause discrepancies during hydration.

Personally, I'm not using SSR at all, so then I would know it's perfectly safe to ignore this warning.

KazariEX commented 13 hours ago

Yes, the warning should be corrected. Perhaps we can try adding some transformations to similar behaviors so that <tbody> can be automatically generated.