fix(compiler-sfc): only transform relative asset URLs (#628)

This commit is contained in:
Sören Schwert 2020-01-20 15:57:17 +01:00 committed by Evan You
parent 787ac5f74e
commit c71ca354b9
8 changed files with 67 additions and 30 deletions

View File

@ -33,7 +33,9 @@ export function render() {
return (openBlock(), createBlock(Fragment, null, [ return (openBlock(), createBlock(Fragment, null, [
createVNode(\\"img\\", { src: _imports_0 }), createVNode(\\"img\\", { src: _imports_0 }),
createVNode(\\"img\\", { src: _imports_1 }), 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 */)) ], 64 /* STABLE_FRAGMENT */))
}" }"
`; `;

View File

@ -12,6 +12,7 @@ const _hoisted_4 = _imports_0 + ', ' + _imports_0 + '2x'
const _hoisted_5 = _imports_0 + '2x, ' + _imports_0 const _hoisted_5 = _imports_0 + '2x, ' + _imports_0
const _hoisted_6 = _imports_0 + '2x, ' + _imports_0 + '3x' const _hoisted_6 = _imports_0 + '2x, ' + _imports_0 + '3x'
const _hoisted_7 = _imports_0 + ', ' + _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() { export function render() {
const _ctx = this const _ctx = this
@ -43,6 +44,18 @@ export function render() {
createVNode(\\"img\\", { createVNode(\\"img\\", {
src: \\"./logo.png\\", src: \\"./logo.png\\",
srcset: _hoisted_7 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 */)) ], 64 /* STABLE_FRAGMENT */))
}" }"

View File

@ -50,7 +50,7 @@ test('warn missing preprocessor', () => {
}) })
test('transform asset url options', () => { test('transform asset url options', () => {
const input = { source: `<foo bar="baz"/>`, filename: 'example.vue' } const input = { source: `<foo bar="~baz"/>`, filename: 'example.vue' }
// Object option // Object option
const { code: code1 } = compileTemplate({ const { code: code1 } = compileTemplate({
...input, ...input,

View File

@ -20,6 +20,8 @@ describe('compiler sfc: transform asset url', () => {
<img src="./logo.png"/> <img src="./logo.png"/>
<img src="~fixtures/logo.png"/> <img src="~fixtures/logo.png"/>
<img src="~/fixtures/logo.png"/> <img src="~/fixtures/logo.png"/>
<img src="http://example.com/fixtures/logo.png"/>
<img src="/fixtures/logo.png"/>
`) `)
expect(result.code).toMatchSnapshot() expect(result.code).toMatchSnapshot()

View File

@ -24,6 +24,9 @@ describe('compiler sfc: transform srcset', () => {
<img src="./logo.png" srcset="./logo.png 2x, ./logo.png"/> <img src="./logo.png" srcset="./logo.png 2x, ./logo.png"/>
<img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x"/> <img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x"/>
<img src="./logo.png" srcset="./logo.png, ./logo.png 2x, ./logo.png 3x"/> <img src="./logo.png" srcset="./logo.png, ./logo.png 2x, ./logo.png 3x"/>
<img src="/logo.png" srcset="/logo.png, /logo.png 2x"/>
<img src="https://example.com/logo.png" srcset="https://example.com/logo.png, https://example.com/logo.png 2x"/>
<img src="/logo.png" srcset="/logo.png, ./logo.png 2x"/>
`) `)
expect(result.code).toMatchSnapshot() expect(result.code).toMatchSnapshot()

View File

@ -7,7 +7,7 @@ import {
SourceLocation, SourceLocation,
TransformContext TransformContext
} from '@vue/compiler-core' } from '@vue/compiler-core'
import { parseUrl } from './templateUtils' import { isRelativeUrl, parseUrl } from './templateUtils'
export interface AssetURLOptions { export interface AssetURLOptions {
[name: string]: string[] [name: string]: string[]
@ -46,6 +46,7 @@ export const transformAssetUrl: NodeTransform = (
if (attr.type !== NodeTypes.ATTRIBUTE) return if (attr.type !== NodeTypes.ATTRIBUTE) return
if (attr.name !== item) return if (attr.name !== item) return
if (!attr.value) return if (!attr.value) return
if (!isRelativeUrl(attr.value.content)) return
const url = parseUrl(attr.value.content) const url = parseUrl(attr.value.content)
const exp = getImportsExpressionExp( const exp = getImportsExpressionExp(
url.path, url.path,

View File

@ -5,7 +5,7 @@ import {
NodeTypes, NodeTypes,
SimpleExpressionNode SimpleExpressionNode
} from '@vue/compiler-core' } from '@vue/compiler-core'
import { parseUrl } from './templateUtils' import { isRelativeUrl, parseUrl } from './templateUtils'
const srcsetTags = ['img', 'source'] const srcsetTags = ['img', 'source']
@ -36,8 +36,12 @@ export const transformSrcset: NodeTransform = (node, context) => {
return { url, descriptor } 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) const compoundExpression = createCompoundExpression([], attr.loc)
imageCandidates.forEach(({ url, descriptor }, index) => { imageCandidates.forEach(({ url, descriptor }, index) => {
if (isRelativeUrl(url)) {
const { path } = parseUrl(url) const { path } = parseUrl(url)
let exp: SimpleExpressionNode let exp: SimpleExpressionNode
if (path) { if (path) {
@ -63,6 +67,15 @@ export const transformSrcset: NodeTransform = (node, context) => {
} }
compoundExpression.children.push(exp) compoundExpression.children.push(exp)
} }
} else {
const exp = createSimpleExpression(
`"${url}"`,
false,
attr.loc,
true
)
compoundExpression.children.push(exp)
}
const isNotLast = imageCandidates.length - 1 > index const isNotLast = imageCandidates.length - 1 > index
if (descriptor && isNotLast) { if (descriptor && isNotLast) {
compoundExpression.children.push(` + '${descriptor}, ' + `) compoundExpression.children.push(` + '${descriptor}, ' + `)

View File

@ -1,16 +1,19 @@
import { UrlWithStringQuery, parse as uriParse } from 'url' import { UrlWithStringQuery, parse as uriParse } from 'url'
import { isString } from '@vue/shared' 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 // We need an extra transform context API for injecting arbitrary import
// statements. // statements.
export function parseUrl(url: string): UrlWithStringQuery { export function parseUrl(url: string): UrlWithStringQuery {
const firstChar = url.charAt(0) const firstChar = url.charAt(0)
if (firstChar === '.' || firstChar === '~' || firstChar === '@') {
if (firstChar === '~') { if (firstChar === '~') {
const secondChar = url.charAt(1) const secondChar = url.charAt(1)
url = url.slice(secondChar === '/' ? 2 : 1) url = url.slice(secondChar === '/' ? 2 : 1)
} }
}
return parseUriParts(url) return parseUriParts(url)
} }