diff --git a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap index d6d255caf55..5fc06681fe2 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap @@ -33,7 +33,9 @@ export function render() { return (openBlock(), createBlock(Fragment, null, [ createVNode(\\"img\\", { src: _imports_0 }), createVNode(\\"img\\", { src: _imports_1 }), - createVNode(\\"img\\", { src: _imports_1 }) + createVNode(\\"img\\", { src: _imports_1 }), + createVNode(\\"img\\", { src: \\"http://example.com/fixtures/logo.png\\" }), + createVNode(\\"img\\", { src: \\"/fixtures/logo.png\\" }) ], 64 /* STABLE_FRAGMENT */)) }" `; diff --git a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap index 78c4bffabfd..64801570ffe 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap @@ -12,6 +12,7 @@ const _hoisted_4 = _imports_0 + ', ' + _imports_0 + '2x' const _hoisted_5 = _imports_0 + '2x, ' + _imports_0 const _hoisted_6 = _imports_0 + '2x, ' + _imports_0 + '3x' const _hoisted_7 = _imports_0 + ', ' + _imports_0 + '2x, ' + _imports_0 + '3x' +const _hoisted_8 = \\"/logo.png\\" + ', ' + _imports_0 + '2x' export function render() { const _ctx = this @@ -43,6 +44,18 @@ export function render() { createVNode(\\"img\\", { src: \\"./logo.png\\", srcset: _hoisted_7 + }), + createVNode(\\"img\\", { + src: \\"/logo.png\\", + srcset: \\"/logo.png, /logo.png 2x\\" + }), + createVNode(\\"img\\", { + src: \\"https://example.com/logo.png\\", + srcset: \\"https://example.com/logo.png, https://example.com/logo.png 2x\\" + }), + createVNode(\\"img\\", { + src: \\"/logo.png\\", + srcset: _hoisted_8 }) ], 64 /* STABLE_FRAGMENT */)) }" diff --git a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts index fa86618b186..2217f069c0b 100644 --- a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts +++ b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts @@ -50,7 +50,7 @@ test('warn missing preprocessor', () => { }) test('transform asset url options', () => { - const input = { source: ``, filename: 'example.vue' } + const input = { source: ``, filename: 'example.vue' } // Object option const { code: code1 } = compileTemplate({ ...input, diff --git a/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts index 9adbd1a6233..40531d780b4 100644 --- a/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts +++ b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts @@ -20,6 +20,8 @@ describe('compiler sfc: transform asset url', () => { + + `) expect(result.code).toMatchSnapshot() diff --git a/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts b/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts index 660242c931b..7b2e365493d 100644 --- a/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts +++ b/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts @@ -24,6 +24,9 @@ describe('compiler sfc: transform srcset', () => { + + + `) expect(result.code).toMatchSnapshot() diff --git a/packages/compiler-sfc/src/templateTransformAssetUrl.ts b/packages/compiler-sfc/src/templateTransformAssetUrl.ts index a5e943b5fda..e6b0c49893a 100644 --- a/packages/compiler-sfc/src/templateTransformAssetUrl.ts +++ b/packages/compiler-sfc/src/templateTransformAssetUrl.ts @@ -7,7 +7,7 @@ import { SourceLocation, TransformContext } from '@vue/compiler-core' -import { parseUrl } from './templateUtils' +import { isRelativeUrl, parseUrl } from './templateUtils' export interface AssetURLOptions { [name: string]: string[] @@ -46,6 +46,7 @@ export const transformAssetUrl: NodeTransform = ( if (attr.type !== NodeTypes.ATTRIBUTE) return if (attr.name !== item) return if (!attr.value) return + if (!isRelativeUrl(attr.value.content)) return const url = parseUrl(attr.value.content) const exp = getImportsExpressionExp( url.path, diff --git a/packages/compiler-sfc/src/templateTransformSrcset.ts b/packages/compiler-sfc/src/templateTransformSrcset.ts index cf557ec255f..dccebd9e5c6 100644 --- a/packages/compiler-sfc/src/templateTransformSrcset.ts +++ b/packages/compiler-sfc/src/templateTransformSrcset.ts @@ -5,7 +5,7 @@ import { NodeTypes, SimpleExpressionNode } from '@vue/compiler-core' -import { parseUrl } from './templateUtils' +import { isRelativeUrl, parseUrl } from './templateUtils' const srcsetTags = ['img', 'source'] @@ -36,31 +36,44 @@ export const transformSrcset: NodeTransform = (node, context) => { return { url, descriptor } }) + // When srcset does not contain any relative URLs, skip transforming + if (!imageCandidates.some(({ url }) => isRelativeUrl(url))) return + const compoundExpression = createCompoundExpression([], attr.loc) imageCandidates.forEach(({ url, descriptor }, index) => { - const { path } = parseUrl(url) - let exp: SimpleExpressionNode - if (path) { - const importsArray = Array.from(context.imports) - const existingImportsIndex = importsArray.findIndex( - i => i.path === path - ) - if (existingImportsIndex > -1) { - exp = createSimpleExpression( - `_imports_${existingImportsIndex}`, - false, - attr.loc, - true + if (isRelativeUrl(url)) { + const { path } = parseUrl(url) + let exp: SimpleExpressionNode + if (path) { + const importsArray = Array.from(context.imports) + const existingImportsIndex = importsArray.findIndex( + i => i.path === path ) - } else { - exp = createSimpleExpression( - `_imports_${importsArray.length}`, - false, - attr.loc, - true - ) - context.imports.add({ exp, path }) + if (existingImportsIndex > -1) { + exp = createSimpleExpression( + `_imports_${existingImportsIndex}`, + false, + attr.loc, + true + ) + } else { + exp = createSimpleExpression( + `_imports_${importsArray.length}`, + false, + attr.loc, + true + ) + context.imports.add({ exp, path }) + } + compoundExpression.children.push(exp) } + } else { + const exp = createSimpleExpression( + `"${url}"`, + false, + attr.loc, + true + ) compoundExpression.children.push(exp) } const isNotLast = imageCandidates.length - 1 > index diff --git a/packages/compiler-sfc/src/templateUtils.ts b/packages/compiler-sfc/src/templateUtils.ts index bbeafd153df..1040571afc9 100644 --- a/packages/compiler-sfc/src/templateUtils.ts +++ b/packages/compiler-sfc/src/templateUtils.ts @@ -1,15 +1,18 @@ import { UrlWithStringQuery, parse as uriParse } from 'url' import { isString } from '@vue/shared' +export function isRelativeUrl(url: string): boolean { + const firstChar = url.charAt(0) + return firstChar === '.' || firstChar === '~' || firstChar === '@' +} + // We need an extra transform context API for injecting arbitrary import // statements. export function parseUrl(url: string): UrlWithStringQuery { const firstChar = url.charAt(0) - if (firstChar === '.' || firstChar === '~' || firstChar === '@') { - if (firstChar === '~') { - const secondChar = url.charAt(1) - url = url.slice(secondChar === '/' ? 2 : 1) - } + if (firstChar === '~') { + const secondChar = url.charAt(1) + url = url.slice(secondChar === '/' ? 2 : 1) } return parseUriParts(url) }