Skip to content

Commit 253f91a

Browse files
committed
fix: better error messages for invalid HTML trees
closes #13331
1 parent 3fa08d5 commit 253f91a

File tree

19 files changed

+81
-64
lines changed

19 files changed

+81
-64
lines changed

.changeset/green-pumpkins-ring.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'svelte': patch
3+
---
4+
5+
fix: better error messages for invalid HTML trees

documentation/docs/98-reference/.generated/compile-errors.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ A component cannot have a default export
481481
### node_invalid_placement
482482

483483
```
484-
%thing% is invalid inside `<%parent%>`
484+
%message%
485485
```
486486

487487
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:

documentation/docs/98-reference/.generated/compile-warnings.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,7 +643,7 @@ Svelte 5 components are no longer classes. Instantiate them using `mount` or `hy
643643
### node_invalid_placement_ssr
644644

645645
```
646-
%thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
646+
%message%. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
647647
```
648648

649649
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:

packages/svelte/messages/compile-errors/template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@
190190
191191
## node_invalid_placement
192192

193-
> %thing% is invalid inside `<%parent%>`
193+
> %message%
194194
195195
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
196196

packages/svelte/messages/compile-warnings/template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
4141
## node_invalid_placement_ssr
4242

43-
> %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
43+
> %message%. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
4444
4545
HTML restricts where certain elements can appear. In case of a violation the browser will 'repair' the HTML in a way that breaks Svelte's assumptions about the structure of your components. Some examples:
4646

packages/svelte/src/compiler/errors.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,14 +1024,13 @@ export function mixed_event_handler_syntaxes(node, name) {
10241024
}
10251025

10261026
/**
1027-
* %thing% is invalid inside `<%parent%>`
1027+
* %message%
10281028
* @param {null | number | NodeLike} node
1029-
* @param {string} thing
1030-
* @param {string} parent
1029+
* @param {string} message
10311030
* @returns {never}
10321031
*/
1033-
export function node_invalid_placement(node, thing, parent) {
1034-
e(node, "node_invalid_placement", `${thing} is invalid inside \`<${parent}>\``);
1032+
export function node_invalid_placement(node, message) {
1033+
e(node, "node_invalid_placement", `${message}`);
10351034
}
10361035

10371036
/**

packages/svelte/src/compiler/phases/2-analyze/visitors/ExpressionTag.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export function ExpressionTag(node, context) {
1212
const in_attribute = context.path.at(-1)?.type === 'Attribute';
1313

1414
if (!in_attribute && context.state.parent_element) {
15-
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
16-
e.node_invalid_placement(node, '`{expression}`', context.state.parent_element);
15+
const message = is_tag_valid_with_parent('#text', context.state.parent_element);
16+
if (message) {
17+
e.node_invalid_placement(node, message);
1718
}
1819
}
1920

packages/svelte/src/compiler/phases/2-analyze/visitors/RegularElement.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,12 @@ export function RegularElement(node, context) {
114114

115115
if (!past_parent) {
116116
if (ancestor.type === 'RegularElement' && ancestor.name === context.state.parent_element) {
117-
if (!is_tag_valid_with_parent(node.name, context.state.parent_element)) {
117+
const message = is_tag_valid_with_parent(node.name, context.state.parent_element);
118+
if (message) {
118119
if (only_warn) {
119-
w.node_invalid_placement_ssr(
120-
node,
121-
`\`<${node.name}>\``,
122-
context.state.parent_element
123-
);
120+
w.node_invalid_placement_ssr(node, message);
124121
} else {
125-
e.node_invalid_placement(node, `\`<${node.name}>\``, context.state.parent_element);
122+
e.node_invalid_placement(node, message);
126123
}
127124
}
128125

@@ -131,11 +128,12 @@ export function RegularElement(node, context) {
131128
} else if (ancestor.type === 'RegularElement') {
132129
ancestors.push(ancestor.name);
133130

134-
if (!is_tag_valid_with_ancestor(node.name, ancestors)) {
131+
const message = is_tag_valid_with_ancestor(node.name, ancestors);
132+
if (message) {
135133
if (only_warn) {
136-
w.node_invalid_placement_ssr(node, `\`<${node.name}>\``, ancestor.name);
134+
w.node_invalid_placement_ssr(node, message);
137135
} else {
138-
e.node_invalid_placement(node, `\`<${node.name}>\``, ancestor.name);
136+
e.node_invalid_placement(node, message);
139137
}
140138
}
141139
} else if (

packages/svelte/src/compiler/phases/2-analyze/visitors/Text.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export function Text(node, context) {
1212
const in_attribute = context.path.at(-1)?.type === 'Attribute';
1313

1414
if (!in_attribute && context.state.parent_element && regex_not_whitespace.test(node.data)) {
15-
if (!is_tag_valid_with_parent('#text', context.state.parent_element)) {
16-
e.node_invalid_placement(node, 'Text node', context.state.parent_element);
15+
const message = is_tag_valid_with_parent('#text', context.state.parent_element);
16+
if (message) {
17+
e.node_invalid_placement(node, message);
1718
}
1819
}
1920
}

packages/svelte/src/compiler/warnings.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -763,13 +763,12 @@ export function event_directive_deprecated(node, name) {
763763
}
764764

765765
/**
766-
* %thing% is invalid inside `<%parent%>`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
766+
* %message%. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a `hydration_mismatch` warning
767767
* @param {null | NodeLike} node
768-
* @param {string} thing
769-
* @param {string} parent
768+
* @param {string} message
770769
*/
771-
export function node_invalid_placement_ssr(node, thing, parent) {
772-
w(node, "node_invalid_placement_ssr", `${thing} is invalid inside \`<${parent}>\`. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a \`hydration_mismatch\` warning`);
770+
export function node_invalid_placement_ssr(node, message) {
771+
w(node, "node_invalid_placement_ssr", `${message}. When rendering this component on the server, the resulting HTML will be modified by the browser, likely resulting in a \`hydration_mismatch\` warning`);
773772
}
774773

775774
/**

0 commit comments

Comments
 (0)