Skip to content

Commit 090b2e3

Browse files
authored
fix(compiler-sfc): preserve hash hrefs on <image> elements (#14756)
1 parent 9667e0d commit 090b2e3

2 files changed

Lines changed: 30 additions & 3 deletions

File tree

packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,29 @@ describe('compiler sfc: transform asset url', () => {
150150
expect(code).toContain(`import _imports_0 from './foo%.png'`)
151151
})
152152

153+
test('should not transform hash fragments on <image>', () => {
154+
// `<image href="#...">` is an in-document fragment reference to another
155+
// SVG element (like `<use>`), not a Node.js subpath import specifier.
156+
const { code } = compileWithAssetUrls(
157+
`<svg><image href="#" /><image href="#myClip" /></svg>`,
158+
{ includeAbsolute: true },
159+
)
160+
expect(code).toContain(`href: "#"`)
161+
expect(code).toContain(`href: "#myClip"`)
162+
expect(code).not.toContain(`from '#'`)
163+
expect(code).not.toContain(`from '#myClip'`)
164+
})
165+
166+
test('should not transform bare `#` value into an import', () => {
167+
// A bare `#` is never a valid module specifier and should always be left
168+
// untouched, even on tags that otherwise support subpath imports.
169+
const { code } = compileWithAssetUrls(`<img src="#" />`, {
170+
includeAbsolute: true,
171+
})
172+
expect(code).toContain(`src: "#"`)
173+
expect(code).not.toContain(`from '#'`)
174+
})
175+
153176
test('should allow for full base URLs, with paths', () => {
154177
const { code } = compileWithAssetUrls(`<img src="./logo.png" />`, {
155178
base: 'http://localhost:3000/src/',

packages/compiler-sfc/src/template/transformAssetUrl.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,22 @@ export interface AssetURLOptions {
3535
tags?: AssetURLTagConfig
3636
}
3737

38-
// Built-in attrs that always represent resource URLs. `use` is intentionally
39-
// omitted because its hash-only values may still be fragment references.
38+
// Built-in attrs that always represent resource URLs. `use` and `image` are
39+
// intentionally omitted because their hash-only values are fragment references
40+
// to in-document elements (e.g. `<image href="#myClip" />`), not module
41+
// specifiers.
4042
const resourceUrlTagConfig: AssetURLTagConfig = {
4143
video: ['src', 'poster'],
4244
source: ['src'],
4345
img: ['src'],
44-
image: ['xlink:href', 'href'],
4546
}
4647

4748
export const defaultAssetUrlOptions: Required<AssetURLOptions> = {
4849
base: null,
4950
includeAbsolute: false,
5051
tags: {
5152
...resourceUrlTagConfig,
53+
image: ['xlink:href', 'href'],
5254
use: ['xlink:href', 'href'],
5355
},
5456
}
@@ -125,6 +127,8 @@ export const transformAssetUrl: NodeTransform = (
125127
if (
126128
isExternalUrl(urlValue) ||
127129
isDataUrl(urlValue) ||
130+
// a bare `#` is never a valid import specifier
131+
urlValue === '#' ||
128132
(isHashOnlyValue && !canTransformHashImport(node.tag, attr.name)) ||
129133
(!options.includeAbsolute && !isRelativeUrl(urlValue))
130134
) {

0 commit comments

Comments
 (0)