diff --git a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap index 998eeae568d..e1c962a6ff5 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformAssetUrl.spec.ts.snap @@ -32,7 +32,8 @@ export function render(_ctx, _cache) { _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\\" }) + _createVNode(\\"img\\", { src: \\"/fixtures/logo.png\\" }), + _createVNode(\\"img\\", { src: \\"data:image/png;base64,i\\" }) ], 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 75c72ac1947..2f057279908 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap @@ -55,6 +55,10 @@ export function render(_ctx, _cache) { _createVNode(\\"img\\", { src: \\"/logo.png\\", srcset: _hoisted_8 + }), + _createVNode(\\"img\\", { + src: \\"data:image/png;base64,i\\", + srcset: \\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\" }) ], 64 /* STABLE_FRAGMENT */)) }" @@ -104,6 +108,10 @@ export function render(_ctx, _cache) { _createVNode(\\"img\\", { src: \\"/logo.png\\", srcset: \\"/logo.png, /foo/logo.png 2x\\" + }), + _createVNode(\\"img\\", { + src: \\"data:image/png;base64,i\\", + srcset: \\"data:image/png;base64,i 1x, data:image/png;base64,i 2x\\" }) ], 64 /* STABLE_FRAGMENT */)) }" @@ -125,6 +133,7 @@ const _hoisted_7 = _imports_0 + ', ' + _imports_0 + '2x, ' + _imports_0 + '3x' const _hoisted_8 = _imports_1 + ', ' + _imports_1 + '2x' const _hoisted_9 = \\"https://example.com/logo.png\\" + ', ' + \\"https://example.com/logo.png\\" + '2x' const _hoisted_10 = _imports_1 + ', ' + _imports_0 + '2x' +const _hoisted_11 = \\"data:image/png;base64,i\\" + '1x, ' + \\"data:image/png;base64,i\\" + '2x' export function render(_ctx, _cache) { return (_openBlock(), _createBlock(_Fragment, null, [ @@ -167,6 +176,10 @@ export function render(_ctx, _cache) { _createVNode(\\"img\\", { src: \\"/logo.png\\", srcset: _hoisted_10 + }), + _createVNode(\\"img\\", { + src: \\"data:image/png;base64,i\\", + srcset: _hoisted_11 }) ], 64 /* STABLE_FRAGMENT */)) }" diff --git a/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts index 71be0e52755..41eb6463cc3 100644 --- a/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts +++ b/packages/compiler-sfc/__tests__/templateTransformAssetUrl.spec.ts @@ -30,6 +30,7 @@ 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 1bba07672b1..9d55dc870ee 100644 --- a/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts +++ b/packages/compiler-sfc/__tests__/templateTransformSrcset.spec.ts @@ -35,6 +35,7 @@ const src = ` + ` describe('compiler sfc: transform srcset', () => { diff --git a/packages/compiler-sfc/__tests__/templateUtils.spec.ts b/packages/compiler-sfc/__tests__/templateUtils.spec.ts index 7b4490fc76f..95bf619be5f 100644 --- a/packages/compiler-sfc/__tests__/templateUtils.spec.ts +++ b/packages/compiler-sfc/__tests__/templateUtils.spec.ts @@ -1,6 +1,7 @@ import { isRelativeUrl, - isExternalUrl + isExternalUrl, + isDataUrl } from '../../compiler-sfc/src/templateUtils' describe('compiler sfc:templateUtils isRelativeUrl', () => { @@ -36,3 +37,17 @@ describe('compiler sfc:templateUtils isExternalUrl', () => { expect(result).toBe(true) }) }) + +describe('compiler sfc:templateUtils isDataUrl', () => { + test('should return true w/ hasn`t media type and encode', () => { + expect(isDataUrl('data:,i')).toBe(true) + }) + + test('should return true w/ media type + encode', () => { + expect(isDataUrl('data:image/png;base64,i')).toBe(true) + }) + + test('should return true w/ media type + hasn`t encode', () => { + expect(isDataUrl('data:image/png,i')).toBe(true) + }) +}) diff --git a/packages/compiler-sfc/src/templateTransformAssetUrl.ts b/packages/compiler-sfc/src/templateTransformAssetUrl.ts index a526d9a9c42..968b0606b8c 100644 --- a/packages/compiler-sfc/src/templateTransformAssetUrl.ts +++ b/packages/compiler-sfc/src/templateTransformAssetUrl.ts @@ -7,7 +7,12 @@ import { SourceLocation, TransformContext } from '@vue/compiler-core' -import { isRelativeUrl, parseUrl, isExternalUrl } from './templateUtils' +import { + isRelativeUrl, + parseUrl, + isExternalUrl, + isDataUrl +} from './templateUtils' import { isArray } from '@vue/shared' export interface AssetURLTagConfig { @@ -99,6 +104,7 @@ export const transformAssetUrl: NodeTransform = ( !assetAttrs.includes(attr.name) || !attr.value || isExternalUrl(attr.value.content) || + isDataUrl(attr.value.content) || attr.value.content[0] === '#' || (!options.includeAbsolute && !isRelativeUrl(attr.value.content)) ) { diff --git a/packages/compiler-sfc/src/templateTransformSrcset.ts b/packages/compiler-sfc/src/templateTransformSrcset.ts index 9790f896cb1..7fcf60754b7 100644 --- a/packages/compiler-sfc/src/templateTransformSrcset.ts +++ b/packages/compiler-sfc/src/templateTransformSrcset.ts @@ -6,7 +6,12 @@ import { NodeTypes, SimpleExpressionNode } from '@vue/compiler-core' -import { isRelativeUrl, parseUrl, isExternalUrl } from './templateUtils' +import { + isRelativeUrl, + parseUrl, + isExternalUrl, + isDataUrl +} from './templateUtils' import { AssetURLOptions, defaultAssetUrlOptions @@ -51,6 +56,15 @@ export const transformSrcset: NodeTransform = ( return { url, descriptor } }) + // for data url need recheck url + for (let i = 0; i < imageCandidates.length; i++) { + if (imageCandidates[i].url.trim().startsWith('data:')) { + imageCandidates[i + 1].url = + imageCandidates[i].url + ',' + imageCandidates[i + 1].url + imageCandidates.splice(i, 1) + } + } + // When srcset does not contain any relative URLs, skip transforming if ( !options.includeAbsolute && @@ -78,6 +92,7 @@ export const transformSrcset: NodeTransform = ( imageCandidates.forEach(({ url, descriptor }, index) => { if ( !isExternalUrl(url) && + !isDataUrl(url) && (options.includeAbsolute || isRelativeUrl(url)) ) { const { path } = parseUrl(url) diff --git a/packages/compiler-sfc/src/templateUtils.ts b/packages/compiler-sfc/src/templateUtils.ts index 40b40199089..6f93d612abf 100644 --- a/packages/compiler-sfc/src/templateUtils.ts +++ b/packages/compiler-sfc/src/templateUtils.ts @@ -11,6 +11,11 @@ export function isExternalUrl(url: string): boolean { return externalRE.test(url) } +const dataUrlRE = /^\s*data:/i +export function isDataUrl(url: string): boolean { + return dataUrlRE.test(url) +} + /** * Parses string url into URL object. */