Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(gatsby-remark-images): Add flag to suppress css background-image to prevent FOUB #17154

Merged
merged 17 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ exports[`gatsby-plugin-sharp queueImageResizing should process immediately when
}
`;

exports[`gatsby-plugin-sharp stats determines if the image is transparent, based on the presence and use of alpha channel 1`] = `
Object {
"isTransparent": false,
}
`;

exports[`gatsby-plugin-sharp stats determines if the image is transparent, based on the presence and use of alpha channel 2`] = `
Object {
"isTransparent": true,
}
`;

exports[`gatsby-plugin-sharp tracedSVG runs on demand 1`] = `
Object {
"aspectRatio": 1,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions packages/gatsby-plugin-sharp/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const {
fixed,
queueImageResizing,
getImageSize,
stats,
} = require(`../`)
const { scheduleJob } = require(`../scheduler`)
scheduleJob.mockResolvedValue(Promise.resolve())
Expand Down Expand Up @@ -373,6 +374,21 @@ describe(`gatsby-plugin-sharp`, () => {
expect(fluidSvg).toMatchSnapshot()
})
})

describe(`stats`, () => {
it(`determines if the image is transparent, based on the presence and use of alpha channel`, async () => {
const result = await stats({ file, args })
expect(result).toMatchSnapshot()
expect(result.isTransparent).toEqual(false)

const alphaResult = await stats({
file: getFileObject(path.join(__dirname, `images/alphatest.png`)),
args,
})
expect(alphaResult).toMatchSnapshot()
expect(alphaResult.isTransparent).toEqual(true)
})
})
})

function getFileObject(absolutePath, name = `test`) {
Expand Down
19 changes: 19 additions & 0 deletions packages/gatsby-plugin-sharp/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,24 @@ async function getTracedSVG({ file, options, cache, reporter }) {
return undefined
}

async function stats({ file, reporter }) {
let imgStats
try {
imgStats = await sharp(file.absolutePath).stats()
} catch (err) {
reportError(
`Failed to get stats for image ${file.absolutePath}`,
err,
reporter
)
return null
}

return {
isTransparent: !imgStats.isOpaque,
}
}

async function fluid({ file, args = {}, reporter, cache }) {
const options = healOptions(getPluginOptions(), args, file.extension)

Expand Down Expand Up @@ -572,3 +590,4 @@ exports.resolutions = fixed
exports.fluid = fluid
exports.fixed = fixed
exports.getImageSize = getImageSize
exports.stats = stats
27 changes: 14 additions & 13 deletions packages/gatsby-remark-images/README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,5 +1,63 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`disableBgImageOnAlpha disables background image on transparent images when disableBgImageOnAlpha === true 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-size: cover; display: block;\\"
></span>
<img
class=\\"gatsby-resp-image-image\\"
alt=\\"some alt\\"
title=\\"some title\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
loading=\\"lazy\\"
/>
</a>
</span>"
`;

exports[`disableBgImageOnAlpha does not disable background image on transparent images when disableBgImageOnAlpha === false 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>
<img
class=\\"gatsby-resp-image-image\\"
alt=\\"some alt\\"
title=\\"some title\\"
src=\\"not-a-real-dir/images/my-image.jpeg\\"
srcset=\\"not-a-real-dir/images/my-image.jpeg, not-a-real-dir/images/my-image.jpeg\\"
sizes=\\"(max-width: 650px) 100vw, 650px\\"
loading=\\"lazy\\"
/>
</a>
</span>"
`;

exports[`it handles goofy nesting properly 1`] = `
"<span
class=\\"gatsby-resp-image-wrapper\\"
Expand Down
35 changes: 35 additions & 0 deletions packages/gatsby-remark-images/src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ jest.mock(`gatsby-plugin-sharp`, () => {
})
},
traceSVG: mockTraceSVG,
stats() {
return Promise.resolve({
isTransparent: true,
})
},
}
})

Expand Down Expand Up @@ -587,3 +592,33 @@ describe(`markdownCaptions`, () => {
expect($(`figcaption`).length).toBe(0)
})
})

describe(`disableBgImageOnAlpha`, () => {
it(`does not disable background image on transparent images when disableBgImageOnAlpha === false`, async () => {
const imagePath = `images/my-image.jpeg`
const content = `![some alt](./${imagePath} "some title")`

const nodes = await plugin(createPluginOptions(content, imagePath), {
disableBgImageOnAlpha: false,
})
expect(nodes.length).toBe(1)

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

it(`disables background image on transparent images when disableBgImageOnAlpha === true`, async () => {
const imagePath = `images/my-image.jpeg`
const content = `![some alt](./${imagePath} "some title")`

const nodes = await plugin(createPluginOptions(content, imagePath), {
disableBgImageOnAlpha: true,
})
expect(nodes.length).toBe(1)

const node = nodes.pop()
expect(node.type).toBe(`html`)
expect(node.value).toMatchSnapshot()
})
})
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 @@ -8,6 +8,7 @@ exports.DEFAULT_OPTIONS = {
withWebp: false,
tracedSVG: false,
loading: `lazy`,
disableBgImageOnAlpha: false,
}

exports.imageClass = `gatsby-resp-image-image`
Expand Down
14 changes: 12 additions & 2 deletions packages/gatsby-remark-images/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const path = require(`path`)
const queryString = require(`query-string`)
const isRelativeUrl = require(`is-relative-url`)
const _ = require(`lodash`)
const { fluid, traceSVG } = require(`gatsby-plugin-sharp`)
const { fluid, stats, traceSVG } = require(`gatsby-plugin-sharp`)
const Promise = require(`bluebird`)
const cheerio = require(`cheerio`)
const slash = require(`slash`)
Expand Down Expand Up @@ -282,10 +282,20 @@ module.exports = (
const imageCaption =
options.showCaptions && getImageCaption(node, overWrites)

let removeBgImage = false
if (options.disableBgImageOnAlpha) {
const imageStats = await stats({ file: imageNode, reporter })
if (imageStats && imageStats.isTransparent) removeBgImage = true
}

const bgImage = !removeBgImage
kimbaudi marked this conversation as resolved.
Show resolved Hide resolved
? ` background-image: url('${placeholderImageData}');`
: ``

let rawHTML = `
<span
class="${imageBackgroundClass}"
style="padding-bottom: ${ratio}; position: relative; bottom: 0; left: 0; background-image: url('${placeholderImageData}'); background-size: cover; display: block;"
style="padding-bottom: ${ratio}; position: relative; bottom: 0; left: 0;${bgImage} background-size: cover; display: block;"
kimbaudi marked this conversation as resolved.
Show resolved Hide resolved
></span>
${imageTag}
`.trim()
Expand Down