mirror of https://github.com/vuejs/core.git
fix(hmr): fix hmr error for hoisted children array in v-for
fix #6978 close #7114
This commit is contained in:
parent
6021d0253e
commit
733437691f
|
@ -593,5 +593,17 @@ describe('compiler: hoistStatic transform', () => {
|
||||||
expect(root.hoists.length).toBe(2)
|
expect(root.hoists.length).toBe(2)
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('clone hoisted array children in HMR mode', () => {
|
||||||
|
const root = transformWithHoist(`<div><span class="hi"></span></div>`, {
|
||||||
|
hmr: true
|
||||||
|
})
|
||||||
|
expect(root.hoists.length).toBe(2)
|
||||||
|
expect(root.codegenNode).toMatchObject({
|
||||||
|
children: {
|
||||||
|
content: '[..._hoisted_2]'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -256,6 +256,13 @@ export interface TransformOptions
|
||||||
* needed to render inline CSS variables on component root
|
* needed to render inline CSS variables on component root
|
||||||
*/
|
*/
|
||||||
ssrCssVars?: string
|
ssrCssVars?: string
|
||||||
|
/**
|
||||||
|
* Whether to compile the template assuming it needs to handle HMR.
|
||||||
|
* Some edge cases may need to generate different code for HMR to work
|
||||||
|
* correctly, e.g. #6938, #7138
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
hmr?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CodegenOptions extends SharedTransformCodegenOptions {
|
export interface CodegenOptions extends SharedTransformCodegenOptions {
|
||||||
|
|
|
@ -129,6 +129,7 @@ export function createTransformContext(
|
||||||
filename = '',
|
filename = '',
|
||||||
prefixIdentifiers = false,
|
prefixIdentifiers = false,
|
||||||
hoistStatic = false,
|
hoistStatic = false,
|
||||||
|
hmr = false,
|
||||||
cacheHandlers = false,
|
cacheHandlers = false,
|
||||||
nodeTransforms = [],
|
nodeTransforms = [],
|
||||||
directiveTransforms = {},
|
directiveTransforms = {},
|
||||||
|
@ -155,6 +156,7 @@ export function createTransformContext(
|
||||||
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
||||||
prefixIdentifiers,
|
prefixIdentifiers,
|
||||||
hoistStatic,
|
hoistStatic,
|
||||||
|
hmr,
|
||||||
cacheHandlers,
|
cacheHandlers,
|
||||||
nodeTransforms,
|
nodeTransforms,
|
||||||
directiveTransforms,
|
directiveTransforms,
|
||||||
|
|
|
@ -140,9 +140,16 @@ function walk(
|
||||||
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||||
isArray(node.codegenNode.children)
|
isArray(node.codegenNode.children)
|
||||||
) {
|
) {
|
||||||
node.codegenNode.children = context.hoist(
|
const hoisted = context.hoist(
|
||||||
createArrayExpression(node.codegenNode.children)
|
createArrayExpression(node.codegenNode.children)
|
||||||
)
|
)
|
||||||
|
// #6978, #7138, #7114
|
||||||
|
// a hoisted children array inside v-for can caused HMR errors since
|
||||||
|
// it might be mutated when mounting the v-for list
|
||||||
|
if (context.hmr) {
|
||||||
|
hoisted.content = `[...${hoisted.content}]`
|
||||||
|
}
|
||||||
|
node.codegenNode.children = hoisted
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,6 +212,7 @@ function doCompileTemplate({
|
||||||
slotted,
|
slotted,
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
...compilerOptions,
|
...compilerOptions,
|
||||||
|
hmr: !isProd,
|
||||||
nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
|
nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
|
||||||
filename,
|
filename,
|
||||||
onError: e => errors.push(e),
|
onError: e => errors.push(e),
|
||||||
|
|
|
@ -20,7 +20,7 @@ const { createRecord, rerender, reload } = __VUE_HMR_RUNTIME__
|
||||||
registerRuntimeCompiler(compileToFunction)
|
registerRuntimeCompiler(compileToFunction)
|
||||||
|
|
||||||
function compileToFunction(template: string) {
|
function compileToFunction(template: string) {
|
||||||
const { code } = baseCompile(template)
|
const { code } = baseCompile(template, { hoistStatic: true, hmr: true })
|
||||||
const render = new Function('Vue', code)(
|
const render = new Function('Vue', code)(
|
||||||
runtimeTest
|
runtimeTest
|
||||||
) as InternalRenderFunction
|
) as InternalRenderFunction
|
||||||
|
@ -567,4 +567,40 @@ describe('hot module replacement', () => {
|
||||||
rerender(parentId, compileToFunction(`<Child>2</Child>`))
|
rerender(parentId, compileToFunction(`<Child>2</Child>`))
|
||||||
expect(serializeInner(root)).toBe(`2`)
|
expect(serializeInner(root)).toBe(`2`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// #6978, #7138, #7114
|
||||||
|
test('hoisted children array inside v-for', () => {
|
||||||
|
const root = nodeOps.createElement('div')
|
||||||
|
const appId = 'test-app-id'
|
||||||
|
const App: ComponentOptions = {
|
||||||
|
__hmrId: appId,
|
||||||
|
render: compileToFunction(
|
||||||
|
`<div v-for="item of 2">
|
||||||
|
<div>1</div>
|
||||||
|
</div>
|
||||||
|
<p>2</p>
|
||||||
|
<p>3</p>`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
createRecord(appId, App)
|
||||||
|
|
||||||
|
render(h(App), root)
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div><div>1</div></div><div><div>1</div></div><p>2</p><p>3</p>`
|
||||||
|
)
|
||||||
|
|
||||||
|
// move the <p>3</p> into the <div>1</div>
|
||||||
|
rerender(
|
||||||
|
appId,
|
||||||
|
compileToFunction(
|
||||||
|
`<div v-for="item of 2">
|
||||||
|
<div>1<p>3</p></div>
|
||||||
|
</div>
|
||||||
|
<p>2</p>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
expect(serializeInner(root)).toBe(
|
||||||
|
`<div><div>1<p>3</p></div></div><div><div>1<p>3</p></div></div><p>2</p>`
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue