feat(compiler-sfc): transform srcset (#501)
This commit is contained in:
parent
74fd6635ce
commit
cf2a0b281f
@ -0,0 +1,49 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`compiler sfc: transform srcset transform srcset 1`] = `
|
||||||
|
"import { createVNode, createBlock, Fragment, openBlock } from \\"vue\\"
|
||||||
|
import _imports_0 from './logo.png'
|
||||||
|
|
||||||
|
|
||||||
|
const _hoisted_1 = _imports_0
|
||||||
|
const _hoisted_2 = _imports_0 + '2x'
|
||||||
|
const _hoisted_3 = _imports_0 + '2x'
|
||||||
|
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'
|
||||||
|
|
||||||
|
export default function render() {
|
||||||
|
const _ctx = this
|
||||||
|
return (openBlock(), createBlock(Fragment, null, [
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_1
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_2
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_3
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_4
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_5
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_6
|
||||||
|
}),
|
||||||
|
createVNode(\\"img\\", {
|
||||||
|
src: \\"./logo.png\\",
|
||||||
|
srcset: _hoisted_7
|
||||||
|
})
|
||||||
|
]))
|
||||||
|
}"
|
||||||
|
`;
|
@ -0,0 +1,31 @@
|
|||||||
|
import { generate, parse, transform } from '@vue/compiler-core'
|
||||||
|
import { transformSrcset } from '../src/templateTransformSrcset'
|
||||||
|
import { transformElement } from '../../compiler-core/src/transforms/transformElement'
|
||||||
|
import { transformBind } from '../../compiler-core/src/transforms/vBind'
|
||||||
|
|
||||||
|
function compileWithSrcset(template: string) {
|
||||||
|
const ast = parse(template)
|
||||||
|
transform(ast, {
|
||||||
|
nodeTransforms: [transformSrcset, transformElement],
|
||||||
|
directiveTransforms: {
|
||||||
|
bind: transformBind
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return generate(ast, { mode: 'module' })
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('compiler sfc: transform srcset', () => {
|
||||||
|
test('transform srcset', () => {
|
||||||
|
const result = compileWithSrcset(`
|
||||||
|
<img src="./logo.png" srcset="./logo.png"/>
|
||||||
|
<img src="./logo.png" srcset="./logo.png 2x"/>
|
||||||
|
<img src="./logo.png" srcset="./logo.png 2x"/>
|
||||||
|
<img src="./logo.png" srcset="./logo.png, ./logo.png 2x"/>
|
||||||
|
<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, ./logo.png 2x, ./logo.png 3x"/>
|
||||||
|
`)
|
||||||
|
|
||||||
|
expect(result.code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
@ -1,5 +1,88 @@
|
|||||||
import { NodeTransform } from '@vue/compiler-core'
|
import {
|
||||||
|
createCompoundExpression,
|
||||||
|
createSimpleExpression,
|
||||||
|
NodeTransform,
|
||||||
|
NodeTypes,
|
||||||
|
SimpleExpressionNode
|
||||||
|
} from '@vue/compiler-core'
|
||||||
|
import { parseUrl } from './templateUtils'
|
||||||
|
|
||||||
export const transformSrcset: NodeTransform = () => {
|
const srcsetTags = ['img', 'source']
|
||||||
// TODO
|
|
||||||
|
interface ImageCandidate {
|
||||||
|
url: string
|
||||||
|
descriptor: string
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
|
||||||
|
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
|
||||||
|
|
||||||
|
export const transformSrcset: NodeTransform = (node, context) => {
|
||||||
|
if (node.type === NodeTypes.ELEMENT) {
|
||||||
|
if (srcsetTags.includes(node.tag) && node.props.length) {
|
||||||
|
node.props.forEach((attr, index) => {
|
||||||
|
if (attr.name === 'srcset' && attr.type === NodeTypes.ATTRIBUTE) {
|
||||||
|
if (!attr.value) return
|
||||||
|
// same logic as in transform-require.js
|
||||||
|
const value = attr.value.content
|
||||||
|
|
||||||
|
const imageCandidates: ImageCandidate[] = value.split(',').map(s => {
|
||||||
|
// The attribute value arrives here with all whitespace, except
|
||||||
|
// normal spaces, represented by escape sequences
|
||||||
|
const [url, descriptor] = s
|
||||||
|
.replace(escapedSpaceCharacters, ' ')
|
||||||
|
.trim()
|
||||||
|
.split(' ', 2)
|
||||||
|
return { url, descriptor }
|
||||||
|
})
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
context.imports.add({ exp, path })
|
||||||
|
}
|
||||||
|
compoundExpression.children.push(exp)
|
||||||
|
}
|
||||||
|
const isNotLast = imageCandidates.length - 1 > index
|
||||||
|
if (descriptor && isNotLast) {
|
||||||
|
compoundExpression.children.push(` + '${descriptor}, ' + `)
|
||||||
|
} else if (descriptor) {
|
||||||
|
compoundExpression.children.push(` + '${descriptor}'`)
|
||||||
|
} else if (isNotLast) {
|
||||||
|
compoundExpression.children.push(` + ', ' + `)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
node.props[index] = {
|
||||||
|
type: NodeTypes.DIRECTIVE,
|
||||||
|
name: 'bind',
|
||||||
|
arg: createSimpleExpression('srcset', true, attr.loc),
|
||||||
|
exp: context.hoist(compoundExpression),
|
||||||
|
modifiers: [],
|
||||||
|
loc: attr.loc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user