Skip to content

Commit

Permalink
Add avif format support to gatsby remark images package (#28927)
Browse files Browse the repository at this point in the history
* Add avif format support to gatsby remark images package

* Add withAvif info into readme

* Add devault value for withAvif option

* Updated snapshot

* Added test for withAvif option
  • Loading branch information
AlexRAV authored Jan 9, 2021
1 parent a455a23 commit 0cb68df
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 52 deletions.
1 change: 1 addition & 0 deletions packages/gatsby-remark-images/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ a reserved keyword `GATSBY_EMPTY_ALT` can be used.
| `backgroundColor` | `white` | Set the background color of the image to match the background image of your design.<br /><br />**Note:**<br />- set this option to `transparent` for a transparent image background.<br /> - set this option to `none` to completely remove the image background. |
| `quality` | `50` | The quality level of the generated files. |
| `withWebp` | `false` | Additionally generate WebP versions alongside your chosen file format. They are added as a srcset with the appropriate mimetype and will be loaded in browsers that support the format. Pass `true` for default support, or an object of options to specifically override those for the WebP files. For example, pass `{ quality: 80 }` to have the WebP images be at quality level 80. |
| `withAvif` | `false` | Additionally generate AVIF versions alongside your chosen file format. They are added as a srcset with the appropriate mimetype and will be loaded in browsers that support the format. Pass `true` for default support, or an object of options to specifically override those for the WebP files. For example, pass `{ quality: 80 }` to have the AVIF images be at quality level 80. |
| `tracedSVG` | `false` | Use traced SVGs for placeholder images instead of the "blur up" effect. Pass `true` for traced SVGs with the default settings (seen [here][3]), or an object of options to override the defaults. For example, pass `{ color: "#F00", turnPolicy: "TURNPOLICY_MAJORITY" }` to change the color of the trace to red and the turn policy to `TURNPOLICY_MAJORITY`. See [`node-potrace` parameter documentation][4] for a full listing and explanation of the available options. |
| `loading` | `lazy` | Set the browser's native lazy loading attribute. One of `lazy`, `eager` or `auto`. |
| `disableBgImageOnAlpha` | `false` | Images containing transparent pixels around the edges results in images with blurry edges. As a result, these images do not work well with the "blur up" technique used in this plugin. As a workaround to disable background images with blurry edges on images containing transparent pixels, enable this setting. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,46 @@ exports[`it transforms images in markdown with query strings 1`] = `
</span>"
`;

exports[`it transforms images in markdown with the "withAvif" option 1`] = `
"<span
class=\\"gatsby-resp-image-wrapper\\"
style=\\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; \\"
>
<a
class=\\"gatsby-resp-image-link\\"
href=\\"not-a-real-dir/images/my-image.jpeg\\"
style=\\"display: block\\"
target=\\"_blank\\"
rel=\\"noopener\\"
>
<span
class=\\"gatsby-resp-image-background-image\\"
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw'); background-size: cover; display: block;\\"
></span>
<picture>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<img
class=\\"gatsby-resp-image-image\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
alt=\\"image\\"
title=\\"image\\"
loading=\\"lazy\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\\"
/>
</picture>
</a>
</span>"
`;

exports[`it transforms images in markdown with the "withWebp" option 1`] = `
"<span
class=\\"gatsby-resp-image-wrapper\\"
Expand All @@ -305,25 +345,25 @@ exports[`it transforms images in markdown with the "withWebp" option 1`] = `
style=\\"padding-bottom: 133.33333333333331%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw'); background-size: cover; display: block;\\"
></span>
<picture>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<img
class=\\"gatsby-resp-image-image\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
alt=\\"image\\"
title=\\"image\\"
loading=\\"lazy\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\\"
/>
</picture>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<source
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
type=\\"undefined\\"
/>
<img
class=\\"gatsby-resp-image-image\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
alt=\\"image\\"
title=\\"image\\"
loading=\\"lazy\\"
style=\\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\\"
/>
</picture>
</a>
</span>"
`;
Expand Down
19 changes: 19 additions & 0 deletions packages/gatsby-remark-images/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,25 @@ test(`it transforms images in markdown with the "withWebp" option`, async () =>
expect(node.value).not.toMatch(`<html>`)
})

test(`it transforms images in markdown with the "withAvif" option`, async () => {
const imagePath = `images/my-image.jpeg`
const content = `
![image](./${imagePath})
`.trim()

const nodes = await plugin(createPluginOptions(content, imagePath), {
withAvif: true,
})

expect(nodes.length).toBe(1)

const node = nodes.pop()
expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
expect(node.value).not.toMatch(`<html>`)
})

test(`it transforms multiple images in markdown`, async () => {
const imagePaths = [`images/my-image.jpeg`, `images/other-image.jpeg`]

Expand Down
1 change: 1 addition & 0 deletions packages/gatsby-remark-images/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ exports.DEFAULT_OPTIONS = {
showCaptions: false,
markdownCaptions: false,
withWebp: false,
withAvif: false,
tracedSVG: false,
loading: `lazy`,
disableBgImageOnAlpha: false,
Expand Down
96 changes: 63 additions & 33 deletions packages/gatsby-remark-images/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -214,44 +214,74 @@ module.exports = (
/>
`.trim()

// if options.withWebp is enabled, generate a webp version and change the image tag to a picture tag
if (options.withWebp) {
const webpFluidResult = await fluid({
file: imageNode,
args: _.defaults(
{ toFormat: `WEBP` },
// override options if it's an object, otherwise just pass through defaults
options.withWebp === true ? {} : options.withWebp,
options
),
reporter,
})
const formatConfigs = [
{
propertyName: `withAvif`,
format: `AVIF`,
},
{
propertyName: `withWebp`,
format: `WEBP`,
},
]

const enabledFormatConfigs = formatConfigs.filter(
({ propertyName }) => options[propertyName]
)

if (enabledFormatConfigs.length) {
const sourcesHtmlPromises = enabledFormatConfigs.map(
async ({ format, propertyName }) => {
const formatFluidResult = await fluid({
file: imageNode,
args: _.defaults(
{ toFormat: format },
// override options if it's an object, otherwise just pass through defaults
options[propertyName] === true ? {} : options[propertyName],
options
),
reporter,
})

if (!formatFluidResult) {
return null
}

return `
<source
srcset="${formatFluidResult.srcSet}"
sizes="${formatFluidResult.sizes}"
type="${formatFluidResult.srcSetType}"
/>
`.trim()
}
)

const sourcesHtml = (await Promise.all(sourcesHtmlPromises)).filter(
sourceHtml => sourceHtml !== null
)

if (!webpFluidResult) {
if (!sourcesHtml.length) {
return resolve()
}

imageTag = `
<picture>
<source
srcset="${webpFluidResult.srcSet}"
sizes="${webpFluidResult.sizes}"
type="${webpFluidResult.srcSetType}"
/>
<source
srcset="${srcSet}"
sizes="${fluidResult.sizes}"
type="${fluidResult.srcSetType}"
/>
<img
class="${imageClass}"
src="${fallbackSrc}"
alt="${alt}"
title="${title}"
loading="${loading}"
style="${imageStyle}"
/>
</picture>
<picture>
${sourcesHtml.join(``)}
<source
srcset="${srcSet}"
sizes="${fluidResult.sizes}"
type="${fluidResult.srcSetType}"
/>
<img
class="${imageClass}"
src="${fallbackSrc}"
alt="${alt}"
title="${title}"
loading="${loading}"
style="${imageStyle}"
/>
</picture>
`.trim()
}

Expand Down

0 comments on commit 0cb68df

Please sign in to comment.