fix(compiler-sfc): properly reuse hoisted asset imports

fix #4581
This commit is contained in:
Evan You 2021-09-16 13:33:02 -04:00
parent fc968d607b
commit 06c5bf53ab
3 changed files with 41 additions and 24 deletions

View File

@ -33,14 +33,17 @@ export function render(_ctx, _cache) {
`; `;
exports[`compiler sfc: transform asset url support uri fragment 1`] = ` exports[`compiler sfc: transform asset url support uri fragment 1`] = `
"import { openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\" "import { createElementVNode as _createElementVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
import _imports_0 from '@svg/file.svg' import _imports_0 from '@svg/file.svg'
const _hoisted_1 = _imports_0 + '#fragment' const _hoisted_1 = _imports_0 + '#fragment'
export function render(_ctx, _cache) { export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"use\\", { href: _hoisted_1 })) return (_openBlock(), _createElementBlock(_Fragment, null, [
_createElementVNode(\\"use\\", { href: _hoisted_1 }),
_createElementVNode(\\"use\\", { href: _hoisted_1 })
], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;

View File

@ -41,7 +41,8 @@ describe('compiler sfc: transform asset url', () => {
*/ */
test('support uri fragment', () => { test('support uri fragment', () => {
const result = compileWithAssetUrls( const result = compileWithAssetUrls(
'<use href="~@svg/file.svg#fragment"></use>' '<use href="~@svg/file.svg#fragment"></use>' +
'<use href="~@svg/file.svg#fragment"></use>'
) )
expect(result.code).toMatchSnapshot() expect(result.code).toMatchSnapshot()

View File

@ -5,6 +5,7 @@ import {
ExpressionNode, ExpressionNode,
NodeTransform, NodeTransform,
NodeTypes, NodeTypes,
SimpleExpressionNode,
SourceLocation, SourceLocation,
TransformContext TransformContext
} from '@vue/compiler-core' } from '@vue/compiler-core'
@ -153,30 +154,42 @@ function getImportsExpressionExp(
context: TransformContext context: TransformContext
): ExpressionNode { ): ExpressionNode {
if (path) { if (path) {
const existing = context.imports.find(i => i.path === path) let name: string
if (existing) { let exp: SimpleExpressionNode
return existing.exp as ExpressionNode const existingIndex = context.imports.findIndex(i => i.path === path)
} if (existingIndex > -1) {
const name = `_imports_${context.imports.length}` name = `_imports_${existingIndex}`
const exp = createSimpleExpression( exp = context.imports[existingIndex].exp as SimpleExpressionNode
name,
false,
loc,
ConstantTypes.CAN_HOIST
)
context.imports.push({ exp, path })
if (hash && path) {
return context.hoist(
createSimpleExpression(
`${name} + '${hash}'`,
false,
loc,
ConstantTypes.CAN_HOIST
)
)
} else { } else {
name = `_imports_${context.imports.length}`
exp = createSimpleExpression(name, false, loc, ConstantTypes.CAN_HOIST)
context.imports.push({ exp, path })
}
if (!hash) {
return exp return exp
} }
const hashExp = `${name} + '${hash}'`
const existingHoistIndex = context.hoists.findIndex(h => {
return (
h &&
h.type === NodeTypes.SIMPLE_EXPRESSION &&
!h.isStatic &&
h.content === hashExp
)
})
if (existingHoistIndex > -1) {
return createSimpleExpression(
`_hoisted_${existingHoistIndex + 1}`,
false,
loc,
ConstantTypes.CAN_HOIST
)
}
return context.hoist(
createSimpleExpression(hashExp, false, loc, ConstantTypes.CAN_HOIST)
)
} else { } else {
return createSimpleExpression(`''`, false, loc, ConstantTypes.CAN_HOIST) return createSimpleExpression(`''`, false, loc, ConstantTypes.CAN_HOIST)
} }