fix: support subpath import urls in asset urls transformation

This commit is contained in:
Haoqun Jiang 2025-03-16 16:57:19 +08:00
parent d48937fb95
commit 66299535a3
No known key found for this signature in database
GPG Key ID: BC1665FD8DE94CD5
3 changed files with 46 additions and 2 deletions

View File

@ -114,6 +114,12 @@ describe('compiler sfc: transform asset url', () => {
expect(code).toMatch(`"xlink:href": "#myCircle"`)
})
// #9919
test('should transform subpath import paths', () => {
const { code } = compileWithAssetUrls(`<img src="#src/assets/vue.svg" />`)
expect(code).toContain(`_imports_0 from '#src/assets/vue.svg'`)
})
test('should allow for full base URLs, with paths', () => {
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
base: 'http://localhost:3000/src/',

View File

@ -3,7 +3,12 @@ import { isString } from '@vue/shared'
export function isRelativeUrl(url: string): boolean {
const firstChar = url.charAt(0)
return firstChar === '.' || firstChar === '~' || firstChar === '@'
return (
firstChar === '.' ||
firstChar === '~' ||
firstChar === '@' ||
firstChar === '#'
)
}
const externalRE = /^(https?:)?\/\//

View File

@ -101,13 +101,19 @@ export const transformAssetUrl: NodeTransform = (
const assetAttrs = (attrs || []).concat(wildCardAttrs || [])
node.props.forEach((attr, index) => {
const isHashFragment =
node.tag === 'use' &&
attr.type === NodeTypes.ATTRIBUTE &&
(attr.name === 'href' || attr.name === 'xlink:href') &&
attr.value?.content[0] === '#'
if (
attr.type !== NodeTypes.ATTRIBUTE ||
!assetAttrs.includes(attr.name) ||
!attr.value ||
isExternalUrl(attr.value.content) ||
isDataUrl(attr.value.content) ||
attr.value.content[0] === '#' ||
isHashFragment ||
(!options.includeAbsolute && !isRelativeUrl(attr.value.content))
) {
return
@ -210,6 +216,33 @@ function getImportsExpressionExp(
)
}
return context.hoist(finalExp)
} else if (hash) {
// Hash without path, e.g. subpath import
let name: string
let exp: SimpleExpressionNode
const existingIndex = context.imports.findIndex(i => i.path === hash)
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_STRINGIFY,
)
// We need to ensure the path is not encoded (to %2F),
// so we decode it back in case it is encoded
context.imports.push({
exp,
path: decodeURIComponent(hash),
})
}
return exp
} else {
return createSimpleExpression(`''`, false, loc, ConstantTypes.CAN_STRINGIFY)
}