Skip to content

Commit

Permalink
Option extension added
Browse files Browse the repository at this point in the history
  • Loading branch information
rymka1989 committed Jan 29, 2022
1 parent 8b02ab6 commit 5e04605
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 123 deletions.
41 changes: 24 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ posthtml()
.process(html/*, options */)
.then(result => fs.writeFileSync('./after.html', result.html));
```
## Example
## Example

Before:
``` html
Expand All @@ -47,39 +47,46 @@ After:

## Options

#### `extension`

Type: `string`
Default: `.webp`
Description: *Add custom extension or even prefix*
Example: `image.jpg => image.jpg?as=webp (instead of image.jpg.webp)`

#### `replaceExtension`

Type: `Boolean`
Default: `false`
Description: *Replace the extension of the source image with .webp instead of appending .webp to the original filename*
Type: `Boolean`
Default: `false`
Description: *Replace the extension of the source image with .webp instead of appending .webp to the original filename*
Example: `image.jpg => image.webp (instead of image.jpg.webp)`

#### `classIgnore`

Type: `Array<string>`
Default: `[]`
Description: *list of classes for which the transformation will be ignored*
Example: `classIgnore: ['ignore-webp']` will ignore transformation for images with the class `ignore-web`
Type: `Array<string>`
Default: `[]`
Description: *list of classes for which the transformation will be ignored*
Example: `classIgnore: ['ignore-webp']` will ignore transformation for images with the class `ignore-web`

#### `extensionIgnore`

Type: `Array<string>`
Default: `[]`
Description: *list of extension for which the transformation will be ignored*
Type: `Array<string>`
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. Use it if you have lazy attribute for `srcset` on your images. It will be set on created `<source>` to later be processed by external lazy loading library.*
Type: `String`
Default: `data-srcset`
Description: *The attribute used for lazy webp loading. Use it if you have lazy attribute for `srcset` on your images. 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.*
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)
Expand Down
216 changes: 110 additions & 106 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,117 +1,121 @@
'use strict'

module.exports = function (options) {
if (!options) {
options = {}
}

if (options.classIgnore === undefined) {
options.classIgnore = []
}

if (options.extensionIgnore === undefined) {
options.extensionIgnore = []
}

if (options.replaceExtension === undefined) {
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(' ')) || []
// 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
if (isIgnore) return imgNode
switch (imgNode.tag) {
case 'amp-img':
return getAmpPicture(imgNode, options)
default:
return getPicture(imgNode, options)
}
})

return tree
}
if (!options) {
options = {}
}

if (options.classIgnore === undefined) {
options.classIgnore = []
}

if (options.extensionIgnore === undefined) {
options.extensionIgnore = []
}

if (options.replaceExtension === undefined) {
options.replaceExtension = false
}

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

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

if (options.extension === undefined) {
options.extension = '.webp'
}

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(' ')) || []
// 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
if (isIgnore) return imgNode
switch (imgNode.tag) {
case 'amp-img':
return getAmpPicture(imgNode, options)
default:
return getPicture(imgNode, options)
}
})

return tree
}
}

function removeExtension (filename) {
var extIndex = filename.lastIndexOf('.')
if (extIndex === -1) {
// Filename has no extension
return filename
} else {
return filename.substring(0, extIndex)
}
function removeExtension(filename) {
var extIndex = filename.lastIndexOf('.')
if (extIndex === -1) {
// Filename has no extension
return filename
} else {
return filename.substring(0, extIndex)
}
}

function getAmpPicture (imgNode, options) {
imgNode.skip = true

var src = imgNode.attrs.src
if (options.replaceExtension) {
src = removeExtension(src)
}
src += '.webp'
return {
tag: 'amp-img',
attrs: {
...imgNode.attrs,
src
},
content: [
{
...imgNode,
function getAmpPicture(imgNode, options) {
imgNode.skip = true

var src = imgNode.attrs.src
if (options.replaceExtension) {
src = removeExtension(src)
}
src += options.extension
return {
tag: 'amp-img',
attrs: {
...imgNode.attrs,
fallback: ''
}
}
]
}
...imgNode.attrs,
src
},
content: [
{
...imgNode,
attrs: {
...imgNode.attrs,
fallback: ''
}
}
]
}
}

function getPicture (imgNode, options) {
imgNode.skip = true
var srcset = (imgNode.attrs.srcset || imgNode.attrs[options.lazySrcset] || imgNode.attrs[options.lazySrc] || imgNode.attrs.src)
.split(',')
.filter(Boolean)
.map(value => {
value = value.trim().split(/\s/)
var path = options.replaceExtension ? removeExtension(value[0]) : value[0]
var size = value[1]

return [path + '.webp', size].filter(Boolean).join(' ')
})
.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: sourceAttrs
},
imgNode
]
}
function getPicture(imgNode, options) {
imgNode.skip = true
var srcset = (imgNode.attrs.srcset || imgNode.attrs[options.lazySrcset] || imgNode.attrs[options.lazySrc] || imgNode.attrs.src)
.split(',')
.filter(Boolean)
.map(value => {
value = value.trim().split(/\s/)
var path = options.replaceExtension ? removeExtension(value[0]) : value[0]
var size = value[1]

return [path + options.extension, size].filter(Boolean).join(' ')
})
.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: sourceAttrs
},
imgNode
]
}
}

0 comments on commit 5e04605

Please sign in to comment.