expect(`Hydration attribute mismatch`).toHaveBeenWarned()
})
+ // #11873
+ test('<textarea> with newlines at the beginning', async () => {
+ const render = () => h('textarea', null, '\nhello')
+ const html = await renderToString(createSSRApp({ render }))
+ mountWithHydration(html, render)
+ expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
+ })
+
+ test('<pre> with newlines at the beginning', async () => {
+ const render = () => h('pre', null, '\n')
+ const html = await renderToString(createSSRApp({ render }))
+ mountWithHydration(html, render)
+ expect(`Hydration text content mismatch`).not.toHaveBeenWarned()
+ })
+
test('boolean attr handling', () => {
mountWithHydration(`<input />`, () => h('input', { readonly: false }))
expect(`Hydration attribute mismatch`).not.toHaveBeenWarned()
remove(cur)
}
} else if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
- if (el.textContent !== vnode.children) {
+ // #11873 the HTML parser will "eat" the first newline when parsing
+ // <pre> and <textarea>, so if the client value starts with a newline,
+ // we need to remove it before comparing
+ let clientText = vnode.children as string
+ if (
+ clientText[0] === '\n' &&
+ (el.tagName === 'PRE' || el.tagName === 'TEXTAREA')
+ ) {
+ clientText = clientText.slice(1)
+ }
+ if (el.textContent !== clientText) {
if (!isMismatchAllowed(el, MismatchTypes.TEXT)) {
;(__DEV__ || __FEATURE_PROD_HYDRATION_MISMATCH_DETAILS__) &&
warn(
const isTemplateNode = (node: Node): node is HTMLTemplateElement => {
return (
node.nodeType === DOMNodeTypes.ELEMENT &&
- (node as Element).tagName.toLowerCase() === 'template'
+ (node as Element).tagName === 'TEMPLATE'
)
}