mirror of https://github.com/sveltejs/svelte
chore: improve SSR invalid element error message (#11585)
* chore: improve SSR invalid element error message * move push_element and pop_element into new dev.js file * pass location info, remove unnecessary if (DEV) block * use full filename, basename is not very helpful. also, current_component is guaranteed to not be null * current_element is guaranteed to not be null in pop_element * tweaks * remove message prefix - redundant when filenames are included * add line/column * make message more concise * reduce indirection * only print message once * update test --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/11621/head
parent
e97bc79f02
commit
1087e6fb54
@ -0,0 +1,5 @@
|
||||
---
|
||||
"svelte": patch
|
||||
---
|
||||
|
||||
chore: improve SSR invalid element error message
|
@ -0,0 +1,93 @@
|
||||
import {
|
||||
disallowed_paragraph_contents,
|
||||
interactive_elements,
|
||||
is_tag_valid_with_parent
|
||||
} from '../../constants.js';
|
||||
import { current_component } from './context.js';
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* tag: string;
|
||||
* parent: null | Element;
|
||||
* filename: null | string;
|
||||
* line: number;
|
||||
* column: number;
|
||||
* }} Element
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Element | null}
|
||||
*/
|
||||
let parent = null;
|
||||
|
||||
/** @type {Set<string>} */
|
||||
let seen;
|
||||
|
||||
/**
|
||||
* @param {Element} element
|
||||
*/
|
||||
function stringify(element) {
|
||||
if (element.filename === null) return `\`<${element.tag}>\``;
|
||||
return `\`<${element.tag}>\` (${element.filename}:${element.line}:${element.column})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('#server').Payload} payload
|
||||
* @param {Element} parent
|
||||
* @param {Element} child
|
||||
*/
|
||||
function print_error(payload, parent, child) {
|
||||
var message =
|
||||
`${stringify(child)} cannot contain ${stringify(parent)}\n\n` +
|
||||
'This can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.';
|
||||
|
||||
if ((seen ??= new Set()).has(message)) return;
|
||||
seen.add(message);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(message);
|
||||
payload.head.out += `<script>console.error(${JSON.stringify(message)})</script>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('#server').Payload} payload
|
||||
* @param {string} tag
|
||||
* @param {number} line
|
||||
* @param {number} column
|
||||
*/
|
||||
export function push_element(payload, tag, line, column) {
|
||||
var filename = /** @type {import('#server').Component} */ (current_component).function.filename;
|
||||
var child = { tag, parent, filename, line, column };
|
||||
|
||||
if (parent !== null && !is_tag_valid_with_parent(tag, parent.tag)) {
|
||||
print_error(payload, parent, child);
|
||||
}
|
||||
|
||||
if (interactive_elements.has(tag)) {
|
||||
let element = parent;
|
||||
while (element !== null) {
|
||||
if (interactive_elements.has(element.tag)) {
|
||||
print_error(payload, element, child);
|
||||
break;
|
||||
}
|
||||
element = element.parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (disallowed_paragraph_contents.includes(tag)) {
|
||||
let element = parent;
|
||||
while (element !== null) {
|
||||
if (element.tag === 'p') {
|
||||
print_error(payload, element, child);
|
||||
break;
|
||||
}
|
||||
element = element.parent;
|
||||
}
|
||||
}
|
||||
|
||||
parent = child;
|
||||
}
|
||||
|
||||
export function pop_element() {
|
||||
parent = /** @type {Element} */ (parent).parent;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import * as $ from "svelte/internal/server";
|
||||
|
||||
export default function Hello_world($$payload, $$props) {
|
||||
$.push(false);
|
||||
$.push();
|
||||
$$payload.out += `<h1>hello world</h1>`;
|
||||
$.pop();
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import * as $ from "svelte/internal/server";
|
||||
|
||||
export default function Hmr($$payload, $$props) {
|
||||
$.push(false);
|
||||
$.push();
|
||||
$$payload.out += `<h1>hello world</h1>`;
|
||||
$.pop();
|
||||
}
|
Loading…
Reference in new issue