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(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
|
||||
*/
|
||||
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 {
|
||||
|
|
|
@ -129,6 +129,7 @@ export function createTransformContext(
|
|||
filename = '',
|
||||
prefixIdentifiers = false,
|
||||
hoistStatic = false,
|
||||
hmr = false,
|
||||
cacheHandlers = false,
|
||||
nodeTransforms = [],
|
||||
directiveTransforms = {},
|
||||
|
@ -155,6 +156,7 @@ export function createTransformContext(
|
|||
selfName: nameMatch && capitalize(camelize(nameMatch[1])),
|
||||
prefixIdentifiers,
|
||||
hoistStatic,
|
||||
hmr,
|
||||
cacheHandlers,
|
||||
nodeTransforms,
|
||||
directiveTransforms,
|
||||
|
|
|
@ -140,9 +140,16 @@ function walk(
|
|||
node.codegenNode.type === NodeTypes.VNODE_CALL &&
|
||||
isArray(node.codegenNode.children)
|
||||
) {
|
||||
node.codegenNode.children = context.hoist(
|
||||
const hoisted = context.hoist(
|
||||
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,
|
||||
sourceMap: true,
|
||||
...compilerOptions,
|
||||
hmr: !isProd,
|
||||
nodeTransforms: nodeTransforms.concat(compilerOptions.nodeTransforms || []),
|
||||
filename,
|
||||
onError: e => errors.push(e),
|
||||
|
|
|
@ -20,7 +20,7 @@ const { createRecord, rerender, reload } = __VUE_HMR_RUNTIME__
|
|||
registerRuntimeCompiler(compileToFunction)
|
||||
|
||||
function compileToFunction(template: string) {
|
||||
const { code } = baseCompile(template)
|
||||
const { code } = baseCompile(template, { hoistStatic: true, hmr: true })
|
||||
const render = new Function('Vue', code)(
|
||||
runtimeTest
|
||||
) as InternalRenderFunction
|
||||
|
@ -567,4 +567,40 @@ describe('hot module replacement', () => {
|
|||
rerender(parentId, compileToFunction(`<Child>2</Child>`))
|
||||
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