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`] = `
"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'
const _hoisted_1 = _imports_0 + '#fragment'
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,6 +41,7 @@ describe('compiler sfc: transform asset url', () => {
*/
test('support uri fragment', () => {
const result = compileWithAssetUrls(
'<use href="~@svg/file.svg#fragment"></use>' +
'<use href="~@svg/file.svg#fragment"></use>'
)

View File

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