From c63524feba5360fa8031e12cb74e5df11cdb130b Mon Sep 17 00:00:00 2001 From: sisou Date: Thu, 16 Jan 2020 09:25:41 +0100 Subject: [PATCH 1/2] fix(compiler): only transform relative asset URLs --- .../templateTransformAssetUrl.spec.ts.snap | 4 +- .../templateTransformSrcset.spec.ts.snap | 15 ++++++ .../__tests__/compileTemplate.spec.ts | 2 +- .../templateTransformAssetUrl.spec.ts | 2 + .../__tests__/templateTransformSrcset.spec.ts | 3 ++ .../src/templateTransformAssetUrl.ts | 26 ++++++--- .../src/templateTransformSrcset.ts | 54 +++++++++++-------- packages/compiler-sfc/src/templateUtils.ts | 13 +++-- 8 files changed, 82 insertions(+), 37 deletions(-) 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..068fe7e7dcc 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap @@ -12,6 +12,9 @@ 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\\" + ', ' + \\"/logo.png\\" + '2x' +const _hoisted_9 = \\"https://example.com/logo.png\\" + ', ' + \\"https://example.com/logo.png\\" + '2x' +const _hoisted_10 = \\"/logo.png\\" + ', ' + _imports_0 + '2x' export function render() { const _ctx = this @@ -43,6 +46,18 @@ export function render() { createVNode(\\"img\\", { src: \\"./logo.png\\", srcset: _hoisted_7 + }), + createVNode(\\"img\\", { + src: \\"/logo.png\\", + srcset: _hoisted_8 + }), + createVNode(\\"img\\", { + src: \\"https://example.com/logo.png\\", + srcset: _hoisted_9 + }), + createVNode(\\"img\\", { + src: \\"/logo.png\\", + srcset: _hoisted_10 }) ], 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..323d995e0e3 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,13 +46,23 @@ export const transformAssetUrl: NodeTransform = ( if (attr.type !== NodeTypes.ATTRIBUTE) return if (attr.name !== item) return if (!attr.value) return - const url = parseUrl(attr.value.content) - const exp = getImportsExpressionExp( - url.path, - url.hash, - attr.loc, - context - ) + let exp: ExpressionNode + if (isRelativeUrl(attr.value.content)) { + const url = parseUrl(attr.value.content) + exp = getImportsExpressionExp( + url.path, + url.hash, + attr.loc, + context + ) + } else { + exp = createSimpleExpression( + `"${attr.value.content}"`, + false, + attr.loc, + true + ) + } node.props[index] = { type: NodeTypes.DIRECTIVE, name: 'bind', diff --git a/packages/compiler-sfc/src/templateTransformSrcset.ts b/packages/compiler-sfc/src/templateTransformSrcset.ts index cf557ec255f..95b76b72347 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'] @@ -38,29 +38,39 @@ export const transformSrcset: NodeTransform = (node, context) => { 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 - ) - } else { - exp = createSimpleExpression( - `_imports_${importsArray.length}`, - 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 ) - 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) } From 537be2c877d64678a069ad724df16da0f088e42c Mon Sep 17 00:00:00 2001 From: sisou Date: Fri, 17 Jan 2020 08:10:37 +0100 Subject: [PATCH 2/2] style(compiler): return early for absolute URLs --- .../templateTransformSrcset.spec.ts.snap | 10 +++----- .../src/templateTransformAssetUrl.ts | 25 ++++++------------- .../src/templateTransformSrcset.ts | 3 +++ 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap index 068fe7e7dcc..64801570ffe 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/templateTransformSrcset.spec.ts.snap @@ -12,9 +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\\" + ', ' + \\"/logo.png\\" + '2x' -const _hoisted_9 = \\"https://example.com/logo.png\\" + ', ' + \\"https://example.com/logo.png\\" + '2x' -const _hoisted_10 = \\"/logo.png\\" + ', ' + _imports_0 + '2x' +const _hoisted_8 = \\"/logo.png\\" + ', ' + _imports_0 + '2x' export function render() { const _ctx = this @@ -49,15 +47,15 @@ export function render() { }), createVNode(\\"img\\", { src: \\"/logo.png\\", - srcset: _hoisted_8 + srcset: \\"/logo.png, /logo.png 2x\\" }), createVNode(\\"img\\", { src: \\"https://example.com/logo.png\\", - srcset: _hoisted_9 + srcset: \\"https://example.com/logo.png, https://example.com/logo.png 2x\\" }), createVNode(\\"img\\", { src: \\"/logo.png\\", - srcset: _hoisted_10 + srcset: _hoisted_8 }) ], 64 /* STABLE_FRAGMENT */)) }" diff --git a/packages/compiler-sfc/src/templateTransformAssetUrl.ts b/packages/compiler-sfc/src/templateTransformAssetUrl.ts index 323d995e0e3..e6b0c49893a 100644 --- a/packages/compiler-sfc/src/templateTransformAssetUrl.ts +++ b/packages/compiler-sfc/src/templateTransformAssetUrl.ts @@ -46,23 +46,14 @@ export const transformAssetUrl: NodeTransform = ( if (attr.type !== NodeTypes.ATTRIBUTE) return if (attr.name !== item) return if (!attr.value) return - let exp: ExpressionNode - if (isRelativeUrl(attr.value.content)) { - const url = parseUrl(attr.value.content) - exp = getImportsExpressionExp( - url.path, - url.hash, - attr.loc, - context - ) - } else { - exp = createSimpleExpression( - `"${attr.value.content}"`, - false, - attr.loc, - true - ) - } + if (!isRelativeUrl(attr.value.content)) return + const url = parseUrl(attr.value.content) + const exp = getImportsExpressionExp( + url.path, + url.hash, + attr.loc, + context + ) node.props[index] = { type: NodeTypes.DIRECTIVE, name: 'bind', diff --git a/packages/compiler-sfc/src/templateTransformSrcset.ts b/packages/compiler-sfc/src/templateTransformSrcset.ts index 95b76b72347..dccebd9e5c6 100644 --- a/packages/compiler-sfc/src/templateTransformSrcset.ts +++ b/packages/compiler-sfc/src/templateTransformSrcset.ts @@ -36,6 +36,9 @@ 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) => { if (isRelativeUrl(url)) {