Skip to content

Commit

Permalink
Support lazy loading
Browse files Browse the repository at this point in the history
  • Loading branch information
andreyvolokitin committed Aug 27, 2020
1 parent ddf8a39 commit 62f0e69
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 6 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,20 @@ Default: `[]`
Description: *list of extension for which the transformation will be ignored*
Example: `extensionIgnore: ['svg']` will ignore transformation for images with the `svg` extension

#### `lazySrcset`

Type: `String`
Default: `data-srcset`
Description: *The attribute used for lazy webp loading. It will be set on created `<source>` to later be processed by external lazy loading library.*
Example: `lazySrcset: 'my-srcset'` will set `my-srcset` attribute on `<source>`

#### `lazySrc`

Type: `String`
Default: `data-src`
Description: *The attribute used for lazy webp loading. The original `<img>` may not contain `src` at all, but instead some custom lazy-loading attribute. Or it may contain just a placeholder image inside `src` which shouldn't be used for webp conversion. `lazySrc` will define a custom attribute name to look at when processing your lazy loaded images. Note that `lazySrcset` is still needed even if `<img>` has only `lazySrc` defined, because `srcset` is the mechanism for defining a source file for the `<source>`. See `lazySrcset` option description.*
Example: `lazySrc: 'my-src'` will convert an image inside `my-src` attribute, instead of regular `src`.

### License [MIT](LICENSE)

[npm]: https://img.shields.io/npm/v/posthtml-webp.svg
Expand Down
25 changes: 19 additions & 6 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,21 @@ module.exports = function (options) {
options.replaceExtension = false
}

if (options.lazySrc === undefined) {
options.lazySrc = 'data-src'
}

if (options.lazySrcset === undefined) {
options.lazySrcset = 'data-srcset'
}

return function posthtmlWebp (tree) {
tree.match([{ tag: 'img' }, { tag: 'amp-img' }], function (imgNode) {
if (imgNode.skip) return imgNode
var classes = (imgNode.attrs && imgNode.attrs.class && imgNode.attrs.class.split(' ')) || []
var extension = imgNode.attrs.src.split('.').pop()
// Extract extension from lazy loading attribute, because it always contains the right image. (`src` can contain "preview")
// Use `src` if there are no lazy loading attributes.
var extension = (imgNode.attrs[options.lazySrc] || imgNode.attrs[options.lazySrcset] || imgNode.attrs.src || imgNode.attrs.srcset).split('.').pop().split(/\s+/)[0]
var isIgnoredByClass = options.classIgnore.filter(className => classes.includes(className)).length > 0
var isIgnoredByExtension = options.extensionIgnore.filter(fileExtension => fileExtension === extension).length > 0
var isIgnore = isIgnoredByClass || isIgnoredByExtension
Expand Down Expand Up @@ -77,7 +87,7 @@ function getAmpPicture (imgNode, options) {
function getPicture (imgNode, options) {
imgNode.skip = true
// set <source> `srcset` to <img> `srcset`, if present; otherwise — use <img> `src`
var srcset = (imgNode.attrs.srcset || imgNode.attrs.src)
var srcset = (imgNode.attrs.srcset || imgNode.attrs[options.lazySrcset] || imgNode.attrs[options.lazySrc] || imgNode.attrs.src)
.split(',')
.filter(Boolean)
.map(value => {
Expand All @@ -89,15 +99,18 @@ function getPicture (imgNode, options) {
})
.join(', ')

var sourceAttrs = {
type: 'image/webp'
}

sourceAttrs[imgNode.attrs[options.lazySrcset] || imgNode.attrs[options.lazySrc] ? options.lazySrcset : 'srcset'] = srcset

return {
tag: 'picture',
content: [
{
tag: 'source',
attrs: {
type: 'image/webp',
srcset
}
attrs: sourceAttrs
},
imgNode
]
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/lazy.expected.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html>
<body>
<picture><source type="image/webp" data-srcset="photo.webp"><img data-src="photo.jpg"></picture>
<picture><source type="image/webp" data-srcset="photo.webp"><img data-src="photo.jpg" src="low-quality-preview.jpg"></picture>
<picture><source type="image/webp" data-srcset="photo-lg.webp 1000w, photo-md.webp 500w, photo-sm.webp 250w"><img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w"></picture>
<picture><source type="image/webp" data-srcset="photo-lg.webp 1000w, photo-md.webp 500w, photo-sm.webp 250w"><img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" src="low-quality-preview.jpg"></picture>
<picture><source type="image/webp" data-srcset="photo-lg.webp 1000w, photo-md.webp 500w, photo-sm.webp 250w"><img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" data-src="photo.jpg"></picture>
<picture><source type="image/webp" data-srcset="photo-lg.webp 1000w, photo-md.webp 500w, photo-sm.webp 250w"><img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" data-src="photo.jpg" src="low-quality-preview.jpg"></picture>
</body>
</html>
11 changes: 11 additions & 0 deletions test/fixtures/lazy.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!doctype html>
<html>
<body>
<img data-src="photo.jpg">
<img data-src="photo.jpg" src="low-quality-preview.jpg">
<img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w">
<img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" src="low-quality-preview.jpg">
<img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" data-src="photo.jpg">
<img data-srcset="photo-lg.jpg 1000w, photo-md.jpg 500w, photo-sm.jpg 250w" data-src="photo.jpg" src="low-quality-preview.jpg">
</body>
</html>
6 changes: 6 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ test('Extension ignore', (t) => {
})
})

test('Lazy attributes', (t) => {
return compare(t, 'lazy', {
replaceExtension: true
})
})

function compare (t, name, options) {
const html = readFileSync(path.join(fixtures, `${name}.html`), 'utf8')
const expected = readFileSync(path.join(fixtures, `${name}.expected.html`), 'utf8')
Expand Down

0 comments on commit 62f0e69

Please sign in to comment.