Skip to content

Commit 69fd7b0

Browse files
AndreKRyyx990803
authored andcommitted
Support for srcset (#953)
* Convert img:srcset to require, similar to img:src * fix srcset import when attribute uses whitespace covers cases like: ``` <img srcset=" ../image.jpg 1x, ../image.2x.jpg 2x, ../image.1920x1280.jpg 1920w " alt="srcset on multiple lines and with extra whitespace"> ``` * Further fixes for whitespace handling Also added a test for srcset.
1 parent 06e97ba commit 69fd7b0

File tree

4 files changed

+75
-1
lines changed

4 files changed

+75
-1
lines changed

lib/template-compiler/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const compiler = require('vue-template-compiler')
55
const transpile = require('vue-template-es2015-compiler')
66
const hotReloadAPIPath = normalize.dep('vue-hot-reload-api')
77
const transformRequire = require('./modules/transform-require')
8+
const transformSrcset = require('./modules/transform-srcset')
89

910
module.exports = function (html) {
1011
this.cacheable()
@@ -13,8 +14,9 @@ module.exports = function (html) {
1314
const vueOptions = this.options.__vueOptions__ || {}
1415
const options = loaderUtils.getOptions(this) || {}
1516

16-
const defaultModules = [transformRequire(options.transformToRequire)]
17+
const defaultModules = [transformRequire(options.transformToRequire), transformSrcset()]
1718
let userModules = vueOptions.compilerModules || options.compilerModules
19+
1820
// for HappyPack cross-process use cases
1921
if (typeof userModules === 'string') {
2022
userModules = require(userModules)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// vue compiler module for transforming `img:srcset` to a number of `require`s
2+
3+
module.exports = function () {
4+
return {
5+
postTransformNode: node => {
6+
transform(node)
7+
}
8+
}
9+
}
10+
11+
function transform (node) {
12+
const tags = ['img', 'source']
13+
14+
if (tags.indexOf(node.tag) !== -1 && node.attrs) {
15+
node.attrs.forEach(attr => {
16+
if (attr.name === 'srcset') {
17+
// same logic as in transform-require.js
18+
var value = attr.value
19+
var isStatic = value.charAt(0) === '"' && value.charAt(value.length - 1) === '"'
20+
if (!isStatic) {
21+
return
22+
}
23+
24+
// http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5
25+
const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g
26+
27+
const imageCandidates = value.substr(1, value.length - 2).split(',').map(s => {
28+
// The attribute value arrives here with all whitespace, except normal spaces, represented by escape sequences
29+
const [url, descriptor] = s.replace(escapedSpaceCharacters, ' ').trim().split(' ', 2)
30+
return { require: urlToRequire(url), descriptor: descriptor }
31+
})
32+
33+
let code = ''
34+
imageCandidates.forEach((o, i, a) => {
35+
code += o.require + ' + " ' + o.descriptor + (i < a.length - 1 ? ', " + ' : '"')
36+
})
37+
38+
attr.value = code
39+
}
40+
})
41+
}
42+
}
43+
44+
function urlToRequire (url) {
45+
// same logic as in transform-require.js
46+
var firstChar = url.charAt(0)
47+
if (firstChar === '.' || firstChar === '~') {
48+
if (firstChar === '~') {
49+
var secondChar = url.charAt(1)
50+
url = '"' + url.slice(secondChar === '/' ? 2 : 1)
51+
}
52+
return `require("${url}")`
53+
}
54+
}

test/fixtures/transform.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink">
55
<image xlink:href="./logo.png" />
66
</svg>
7+
<img src="./logo.png" srcset="./logo.png 2x">
8+
<img src="./logo.png" srcset="./logo.png 2x, ./logo.png 3x">
9+
<img
10+
src="./logo.png"
11+
srcset="
12+
./logo.png 2x,
13+
./logo.png 3x
14+
">
715
</div>
816
</template>
917

test/test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,16 @@ describe('vue-loader', function () {
434434
// image tag (SVG)
435435
expect(includeDataURL(vnode.children[2].children[0].data.attrs['xlink:href'])).to.equal(true)
436436
var style = window.document.querySelector('style').textContent
437+
438+
let dataURL = vnode.children[0].data.attrs.src
439+
440+
// image tag with srcset
441+
expect(vnode.children[4].data.attrs.srcset).to.equal(dataURL + " 2x")
442+
// image tag with srcset with two candidates
443+
expect(vnode.children[6].data.attrs.srcset).to.equal(dataURL + " 2x, " + dataURL + " 3x")
444+
// image tag with multiline srcset
445+
expect(vnode.children[8].data.attrs.srcset).to.equal(dataURL + " 2x, " + dataURL + " 3x")
446+
437447
// style
438448
expect(includeDataURL(style)).to.equal(true)
439449
done()

0 commit comments

Comments
 (0)