From 94c2d735ad378bf05836e74cc47f7ca9523cabdc Mon Sep 17 00:00:00 2001 From: Michal Piechowiak Date: Fri, 25 Nov 2022 10:22:38 +0100 Subject: [PATCH] chore: remove tracedSVG (#37093) * init * gri * update shopify snapshot * gatsby-plugin-sharp tests * update gatsby-remark-images/gatsby-node tests * update gatsby-plugin-image tests * update schema print tests * remove traceSVG unit tests as it was removed * legacy gatsby-image fields * update polyfill tests * update cypress assertion * update contentful cypress assertions * drop few more packages from gatsby-plugin-sharp as they are no onger used * correct IMAGE_CDN fallback for TRACE_SVG * update generateImageData * update e2e-prod/assertions * update unit test * update snapshot * update e2e-dev/assertions * drop more unused * sync yarn.lock * a bit more prod warnings * adjust gatsby-remark-images plugin options warning * add link to gatsby-remark-images warning --- .../integration/gatsby-plugin-image.js | 2 +- .../gatsby-plugin-image.js/english-0.snap.png | Bin 49237 -> 49398 bytes e2e-tests/contentful/snapshots.js | 2 +- .../src/pages/gatsby-plugin-image.js | 4 +- .../remote-file/gatsby-plugin-image.js | 5 +- .../integration/static-image/traced.js | 12 +- .../cypress/integration/remote-file.js | 255 +++++++++-------- .../integration/static-image/traced.js | 21 +- examples/using-contentful/package.json | 3 +- .../gatsby-plugin-image/src/resolver-utils.ts | 6 +- packages/gatsby-plugin-sharp/package.json | 5 +- .../src/__tests__/__snapshots__/index.js.snap | 8 +- .../src/__tests__/index.js | 12 +- .../src/__tests__/trace-svg.js | 270 ------------------ .../gatsby-plugin-sharp/src/image-data.ts | 13 +- packages/gatsby-plugin-sharp/src/index.js | 72 +++-- packages/gatsby-plugin-sharp/src/trace-svg.js | 187 ------------ packages/gatsby-plugin-utils/package.json | 5 +- .../__tests__/gatsby-image-resolver.ts | 12 +- .../graphql/gatsby-image-resolver.ts | 15 +- .../placeholder-handler.ts | 84 +----- packages/gatsby-remark-images/package.json | 1 - .../src/__tests__/__snapshots__/index.js.snap | 62 ++-- .../src/__tests__/gatsby-node.js | 57 +++- .../src/__tests__/index.js | 14 +- .../gatsby-remark-images/src/gatsby-node.js | 32 ++- packages/gatsby-remark-images/src/index.js | 27 +- .../__snapshots__/gatsby-plugin-image.js.snap | 14 +- .../src/__tests__/gatsby-plugin-image.js | 13 +- .../src/gatsby-plugin-image.js | 17 +- .../__snapshots__/create-resolvers.ts.snap | 12 +- .../gatsby-transformer-sharp/package.json | 1 - .../src/customize-schema.js | 79 +++-- .../gatsby-transformer-sharp/src/types.ts | 13 +- .../__tests__/__snapshots__/print.js.snap | 18 +- yarn.lock | 14 +- 36 files changed, 460 insertions(+), 907 deletions(-) delete mode 100644 packages/gatsby-plugin-sharp/src/__tests__/trace-svg.js delete mode 100644 packages/gatsby-plugin-sharp/src/trace-svg.js diff --git a/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js b/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js index 1894fdc4a6134..1678cea7af2d2 100644 --- a/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js +++ b/e2e-tests/contentful/cypress/integration/gatsby-plugin-image.js @@ -78,7 +78,7 @@ describe(`gatsby-plugin-image`, () => { testGatsbyPluginImage(`dominant-color`, hasColorPlaceholder) ) it(`traced`, testConfig, () => - testGatsbyPluginImage(`traced`, hasSVGPlaceholder) + testGatsbyPluginImage(`traced`, hasColorPlaceholder) ) it(`blurred`, testConfig, () => testGatsbyPluginImage(`blurred`, hasBase64Placeholder) diff --git a/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/english-0.snap.png b/e2e-tests/contentful/cypress/snapshots/gatsby-plugin-image.js/english-0.snap.png index 263e5595d6eb466e92eaffe1a536258111a422d2..2fabcb0cced11e58587e207d2444021831b99ca4 100644 GIT binary patch literal 49398 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 EFTGt<8 literal 49237 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 diff --git a/e2e-tests/contentful/snapshots.js b/e2e-tests/contentful/snapshots.js index 2aeca7312618f..273c556c6caef 100644 --- a/e2e-tests/contentful/snapshots.js +++ b/e2e-tests/contentful/snapshots.js @@ -1,5 +1,5 @@ module.exports = { - "__version": "9.6.1", + "__version": "9.7.0", "content-reference": { "content-reference-many-2nd-level-loop": { "1": "
\n

Content Reference: Many (2nd level loop)

\n

[ContentfulNumber]\n 42

\n

[ContentfulText]\n The quick brown fox jumps over the lazy dog.

\n

[ContentfulReference]\n Content Reference: One (Loop A -> B)\n : [\n Content Reference: One (Loop B -> A)\n ]

\n
" diff --git a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js index b444a2080f300..ead0cc27082f0 100644 --- a/e2e-tests/contentful/src/pages/gatsby-plugin-image.js +++ b/e2e-tests/contentful/src/pages/gatsby-plugin-image.js @@ -94,7 +94,9 @@ const GatsbyPluginImagePage = ({ data }) => { ))} -

gatsby-plugin-image: Traced SVG Placeholder

+

+ gatsby-plugin-image: Traced SVG Placeholder (fallback to DOMINANT_COLOR) +

{data.default.nodes.map(node => (
diff --git a/e2e-tests/development-runtime/cypress/integration/remote-file/gatsby-plugin-image.js b/e2e-tests/development-runtime/cypress/integration/remote-file/gatsby-plugin-image.js index 2fac5405bdca6..f5e49c77452ef 100644 --- a/e2e-tests/development-runtime/cypress/integration/remote-file/gatsby-plugin-image.js +++ b/e2e-tests/development-runtime/cypress/integration/remote-file/gatsby-plugin-image.js @@ -126,8 +126,9 @@ describe(`remote-file`, () => { cy.get(".constrained_traced [data-placeholder-image]") .first() .should($el => { - expect($el.prop("tagName")).to.be.equal("IMG") - expect($el.prop("src")).to.contain("data:image/svg+xml,%3csvg") + // traced falls back to DOMINANT_COLOR + expect($el.prop("tagName")).to.be.equal("DIV") + expect($el).to.be.empty }) cy.get(".full [data-placeholder-image]") .first() diff --git a/e2e-tests/development-runtime/cypress/integration/static-image/traced.js b/e2e-tests/development-runtime/cypress/integration/static-image/traced.js index c038f779a1a2c..0efda1ea4fef8 100644 --- a/e2e-tests/development-runtime/cypress/integration/static-image/traced.js +++ b/e2e-tests/development-runtime/cypress/integration/static-image/traced.js @@ -5,12 +5,14 @@ describe(`fixed`, () => { cy.visit(`/static-image/traced`).waitForRouteChange() }) - it(`renders a traced svg`, () => { + it(`traced svg (falls back to DOMINANT_COLOR)`, () => { cy.getTestElement(tracedTestId) - .find(`.gatsby-image-wrapper > img`) - .should(`have.attr`, `src`) - .and(src => { - ;[`data:image/svg+xml`].forEach(part => expect(src).to.include(part)) + .find(`.gatsby-image-wrapper > [data-placeholder-image]`) + .first() + .should($el => { + // traced falls + expect($el.prop("tagName")).to.be.equal("DIV") + expect($el).to.be.empty }) }) diff --git a/e2e-tests/production-runtime/cypress/integration/remote-file.js b/e2e-tests/production-runtime/cypress/integration/remote-file.js index 4ba72ca178b5a..ad5595a4e3bf2 100644 --- a/e2e-tests/production-runtime/cypress/integration/remote-file.js +++ b/e2e-tests/production-runtime/cypress/integration/remote-file.js @@ -1,149 +1,158 @@ -Cypress.on('uncaught:exception', (err) => { - if ((err.message.includes('Minified React error #418') || err.message.includes('Minified React error #423') || err.message.includes('Minified React error #425')) && Cypress.env(`TEST_PLUGIN_OFFLINE`)) { +Cypress.on("uncaught:exception", err => { + if ( + (err.message.includes("Minified React error #418") || + err.message.includes("Minified React error #423") || + err.message.includes("Minified React error #425")) && + Cypress.env(`TEST_PLUGIN_OFFLINE`) + ) { return false } }) describe( - `remote-file`, + `remote-file`, { retries: { runMode: 4, }, }, () => { - beforeEach(() => { - cy.visit(`/remote-file/`).waitForRouteChange() + beforeEach(() => { + cy.visit(`/remote-file/`).waitForRouteChange() - // trigger intersection observer - cy.scrollTo("top") - cy.wait(100) - cy.scrollTo("bottom", { - duration: 500, - }) - cy.wait(500) - }) - - async function testImages(images, expectations) { - for (let i = 0; i < images.length; i++) { - const expectation = expectations[i] - - const res = await fetch(images[i].currentSrc, { - method: "HEAD", + // trigger intersection observer + cy.scrollTo("top") + cy.wait(100) + cy.scrollTo("bottom", { + duration: 500, }) - expect(res.ok).to.be.true - if (expectation.width) { - expect(Math.ceil(images[i].getBoundingClientRect().width)).to.be.equal( - expectation.width - ) - } - if (expectation.height) { - expect(Math.ceil(images[i].getBoundingClientRect().height)).to.be.equal( - expectation.height - ) - } - } - } + cy.wait(500) + }) - it(`should render correct dimensions`, () => { - cy.get('[data-testid="public"]').then(async $urls => { - const urls = Array.from($urls.map((_, $url) => $url.getAttribute("href"))) + async function testImages(images, expectations) { + for (let i = 0; i < images.length; i++) { + const expectation = expectations[i] - for (const url of urls) { - const res = await fetch(url, { + const res = await fetch(images[i].currentSrc, { method: "HEAD", }) expect(res.ok).to.be.true + if (expectation.width) { + expect( + Math.ceil(images[i].getBoundingClientRect().width) + ).to.be.equal(expectation.width) + } + if (expectation.height) { + expect( + Math.ceil(images[i].getBoundingClientRect().height) + ).to.be.equal(expectation.height) + } } - }) - - cy.get(".resize").then(async $imgs => { - await testImages(Array.from($imgs), [ - { - width: 100, - height: 133, - }, - { - width: 100, - height: 160, - }, - { - width: 100, - height: 67, - }, - ]) - }) + } - cy.get(".fixed").then(async $imgs => { - await testImages(Array.from($imgs), [ - { - width: 100, - height: 133, - }, - { - width: 100, - height: 160, - }, - { - width: 100, - height: 67, - }, - ]) - }) + it(`should render correct dimensions`, () => { + cy.get('[data-testid="public"]').then(async $urls => { + const urls = Array.from( + $urls.map((_, $url) => $url.getAttribute("href")) + ) - cy.get(".constrained").then(async $imgs => { - await testImages(Array.from($imgs), [ - { - width: 300, - height: 400, - }, - { - width: 300, - height: 481, - }, - { - width: 300, - height: 200, - }, - ]) - }) + for (const url of urls) { + const res = await fetch(url, { + method: "HEAD", + }) + expect(res.ok).to.be.true + } + }) - cy.get(".full").then(async $imgs => { - await testImages(Array.from($imgs), [ - { - height: 1229, - }, - { - height: 1478, - }, - { - height: 614, - }, - ]) - }) - }) + cy.get(".resize").then(async $imgs => { + await testImages(Array.from($imgs), [ + { + width: 100, + height: 133, + }, + { + width: 100, + height: 160, + }, + { + width: 100, + height: 67, + }, + ]) + }) - it(`should render a placeholder`, () => { - cy.get(".fixed [data-placeholder-image]") - .first() - .should("have.css", "background-color", "rgb(232, 184, 8)") - cy.get(".constrained [data-placeholder-image]") - .first() - .should($el => { - expect($el.prop("tagName")).to.be.equal("IMG") - expect($el.prop("src")).to.contain("data:image/jpg;base64") + cy.get(".fixed").then(async $imgs => { + await testImages(Array.from($imgs), [ + { + width: 100, + height: 133, + }, + { + width: 100, + height: 160, + }, + { + width: 100, + height: 67, + }, + ]) }) - cy.get(".constrained_traced [data-placeholder-image]") - .first() - .should($el => { - expect($el.prop("tagName")).to.be.equal("IMG") - expect($el.prop("src")).to.contain("data:image/svg+xml,%3csvg") + + cy.get(".constrained").then(async $imgs => { + await testImages(Array.from($imgs), [ + { + width: 300, + height: 400, + }, + { + width: 300, + height: 481, + }, + { + width: 300, + height: 200, + }, + ]) }) - cy.get(".full [data-placeholder-image]") - .first() - .should($el => { - expect($el.prop("tagName")).to.be.equal("DIV") - expect($el).to.be.empty + + cy.get(".full").then(async $imgs => { + await testImages(Array.from($imgs), [ + { + height: 1229, + }, + { + height: 1478, + }, + { + height: 614, + }, + ]) }) - }) -}) + }) + + it(`should render a placeholder`, () => { + cy.get(".fixed [data-placeholder-image]") + .first() + .should("have.css", "background-color", "rgb(232, 184, 8)") + cy.get(".constrained [data-placeholder-image]") + .first() + .should($el => { + expect($el.prop("tagName")).to.be.equal("IMG") + expect($el.prop("src")).to.contain("data:image/jpg;base64") + }) + cy.get(".constrained_traced [data-placeholder-image]") + .first() + .should($el => { + // traced falls back to DOMINANT_COLOR + expect($el.prop("tagName")).to.be.equal("DIV") + expect($el).to.be.empty + }) + cy.get(".full [data-placeholder-image]") + .first() + .should($el => { + expect($el.prop("tagName")).to.be.equal("DIV") + expect($el).to.be.empty + }) + }) + } +) diff --git a/e2e-tests/production-runtime/cypress/integration/static-image/traced.js b/e2e-tests/production-runtime/cypress/integration/static-image/traced.js index a030714387422..e364290316848 100644 --- a/e2e-tests/production-runtime/cypress/integration/static-image/traced.js +++ b/e2e-tests/production-runtime/cypress/integration/static-image/traced.js @@ -1,7 +1,12 @@ const tracedTestId = `image-traced` -Cypress.on('uncaught:exception', (err) => { - if ((err.message.includes('Minified React error #418') || err.message.includes('Minified React error #423') || err.message.includes('Minified React error #425')) && Cypress.env(`TEST_PLUGIN_OFFLINE`)) { +Cypress.on("uncaught:exception", err => { + if ( + (err.message.includes("Minified React error #418") || + err.message.includes("Minified React error #423") || + err.message.includes("Minified React error #425")) && + Cypress.env(`TEST_PLUGIN_OFFLINE`) + ) { return false } }) @@ -11,12 +16,14 @@ describe(`fixed`, () => { cy.visit(`/static-image/traced`).waitForRouteChange() }) - it(`renders a traced svg`, () => { + it(`traced svg (falls back to DOMINANT_COLOR)`, () => { cy.getTestElement(tracedTestId) - .find(`.gatsby-image-wrapper > img`) - .should(`have.attr`, `src`) - .and(src => { - ;[`data:image/svg+xml`].forEach(part => expect(src).to.include(part)) + .find(`.gatsby-image-wrapper > [data-placeholder-image]`) + .first() + .should($el => { + // traced falls + expect($el.prop("tagName")).to.be.equal("DIV") + expect($el).to.be.empty }) }) diff --git a/examples/using-contentful/package.json b/examples/using-contentful/package.json index 4a04b83b91de1..f1a66f4698077 100644 --- a/examples/using-contentful/package.json +++ b/examples/using-contentful/package.json @@ -30,6 +30,7 @@ "scripts": { "develop": "gatsby develop", "build": "gatsby build", + "clean": "gatsby clean", "start": "gatsby serve" } -} \ No newline at end of file +} diff --git a/packages/gatsby-plugin-image/src/resolver-utils.ts b/packages/gatsby-plugin-image/src/resolver-utils.ts index 513b6daacca9d..5852d0e76d739 100644 --- a/packages/gatsby-plugin-image/src/resolver-utils.ts +++ b/packages/gatsby-plugin-image/src/resolver-utils.ts @@ -202,9 +202,9 @@ export function getGatsbyImageFieldConfig( type: ImagePlaceholderType.name, description: stripIndent` Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI. + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color.`, }, formats: { diff --git a/packages/gatsby-plugin-sharp/package.json b/packages/gatsby-plugin-sharp/package.json index a8a1313b8bdf2..b7b17d444567e 100644 --- a/packages/gatsby-plugin-sharp/package.json +++ b/packages/gatsby-plugin-sharp/package.json @@ -8,7 +8,6 @@ }, "dependencies": { "@babel/runtime": "^7.15.4", - "@gatsbyjs/potrace": "^2.3.0", "async": "^3.2.4", "bluebird": "^3.7.2", "debug": "^4.3.4", @@ -17,11 +16,9 @@ "gatsby-core-utils": "^4.2.0-next.0", "gatsby-plugin-utils": "^4.2.0-next.0", "lodash": "^4.17.21", - "mini-svg-data-uri": "^1.4.4", "probe-image-size": "^7.2.3", "semver": "^7.3.7", - "sharp": "^0.30.7", - "svgo": "^2.8.0" + "sharp": "^0.30.7" }, "devDependencies": { "@babel/cli": "^7.15.4", diff --git a/packages/gatsby-plugin-sharp/src/__tests__/__snapshots__/index.js.snap b/packages/gatsby-plugin-sharp/src/__tests__/__snapshots__/index.js.snap index ea17e500aba82..4036b74d4cb8c 100644 --- a/packages/gatsby-plugin-sharp/src/__tests__/__snapshots__/index.js.snap +++ b/packages/gatsby-plugin-sharp/src/__tests__/__snapshots__/index.js.snap @@ -1397,7 +1397,7 @@ Object { } `; -exports[`gatsby-plugin-sharp tracedSVG runs on demand 1`] = ` +exports[`gatsby-plugin-sharp tracedSVG runs on demand (and falls back to blurred): fixed 1`] = ` Object { "aspectRatio": 1, "base64": undefined, @@ -1405,12 +1405,12 @@ Object { "originalName": "test.png", "src": "/static/1234/7e516/test.png", "srcSet": "/static/1234/7e516/test.png 1x", - "tracedSVG": "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100'%20height='100'%20viewBox='0%200%20100%20100'%20preserveAspectRatio='none'%3e%3cpath%20d='M41%2024c-18%207-24%2029-11%2043%2015%2017%2044%208%2046-15%201-19-17-34-35-28'%20fill='red'%20fill-rule='evenodd'/%3e%3c/svg%3e", + "tracedSVG": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAABP0lEQVQ4y2P4r8ZANmKgvuZ/agy/VaHojyopmv+CNf/XQCCoCEHNf1VBqv+oM5yVY1giwbBakuG2AkjknzoW/eh2/tdgOCPHYM7OwMDAwAgiGFgYGMJ5GF4og43ApRmuk58JqpMJRjIwMBizMbxTZviPaj8ihCD6rThAStkgljJATWEHc3P5wT5SxdD8B2ztERmQIiYGdAAxSpaF4T2q5TDN4HCaLgZSxMyAE1yQgwY+Fs1zxQloviSPTTMktM7JgVzIiKEH4hElFoavKogAQgltiJA3F0gdOyPC58yw8GsUwhFgUMvVGR4oMqiwogQbhOHLxfBLDcVabIlEneGxEkMMLwMvTLc4M0OdEMN3VfRIxp48/6mDnPdCieGkHCiRflRh+K+JPXljz1IQJ0AzhjrRGQPZC5As+ZeuhQGRmgHU8mT34D0STQAAAABJRU5ErkJggg==", "width": 100, } `; -exports[`gatsby-plugin-sharp tracedSVG runs on demand 2`] = ` +exports[`gatsby-plugin-sharp tracedSVG runs on demand (and falls back to blurred): fluid 1`] = ` Object { "aspectRatio": 1, "base64": undefined, @@ -1425,6 +1425,6 @@ Object { /static/1234/a1812/test.png 50w, /static/1234/7e516/test.png 100w", "srcSetType": "image/png", - "tracedSVG": "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='100'%20height='100'%20viewBox='0%200%20100%20100'%20preserveAspectRatio='none'%3e%3cpath%20d='M41%2024c-18%207-24%2029-11%2043%2015%2017%2044%208%2046-15%201-19-17-34-35-28'%20fill='red'%20fill-rule='evenodd'/%3e%3c/svg%3e", + "tracedSVG": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAACXBIWXMAAAsTAAALEwEAmpwYAAABP0lEQVQ4y2P4r8ZANmKgvuZ/agy/VaHojyopmv+CNf/XQCCoCEHNf1VBqv+oM5yVY1giwbBakuG2AkjknzoW/eh2/tdgOCPHYM7OwMDAwAgiGFgYGMJ5GF4og43ApRmuk58JqpMJRjIwMBizMbxTZviPaj8ihCD6rThAStkgljJATWEHc3P5wT5SxdD8B2ztERmQIiYGdAAxSpaF4T2q5TDN4HCaLgZSxMyAE1yQgwY+Fs1zxQloviSPTTMktM7JgVzIiKEH4hElFoavKogAQgltiJA3F0gdOyPC58yw8GsUwhFgUMvVGR4oMqiwogQbhOHLxfBLDcVabIlEneGxEkMMLwMvTLc4M0OdEMN3VfRIxp48/6mDnPdCieGkHCiRflRh+K+JPXljz1IQJ0AzhjrRGQPZC5As+ZeuhQGRmgHU8mT34D0STQAAAABJRU5ErkJggg==", } `; diff --git a/packages/gatsby-plugin-sharp/src/__tests__/index.js b/packages/gatsby-plugin-sharp/src/__tests__/index.js index e0713939fa4d2..38f7ec1ece1a0 100644 --- a/packages/gatsby-plugin-sharp/src/__tests__/index.js +++ b/packages/gatsby-plugin-sharp/src/__tests__/index.js @@ -588,7 +588,7 @@ describe(`gatsby-plugin-sharp`, () => { expect(result.tracedSVG).toBeUndefined() }) - it(`runs on demand`, async () => { + it(`runs on demand (and falls back to blurred)`, async () => { const args = { maxWidth: 100, width: 100, @@ -602,14 +602,20 @@ describe(`gatsby-plugin-sharp`, () => { args, }) - expect(fixedSvg).toMatchSnapshot() + expect(fixedSvg).toMatchSnapshot(`fixed`) + + expect(fixedSvg.tracedSVG).toMatch(`data:image/png;base64`) + expect(fixedSvg.tracedSVG).not.toMatch(`data:image/svg+xml`) const fluidSvg = await fluid({ file, args, }) - expect(fluidSvg).toMatchSnapshot() + expect(fluidSvg).toMatchSnapshot(`fluid`) + + expect(fluidSvg.tracedSVG).toMatch(`data:image/png;base64`) + expect(fluidSvg.tracedSVG).not.toMatch(`data:image/svg+xml`) }) }) diff --git a/packages/gatsby-plugin-sharp/src/__tests__/trace-svg.js b/packages/gatsby-plugin-sharp/src/__tests__/trace-svg.js deleted file mode 100644 index 11cf82ac17338..0000000000000 --- a/packages/gatsby-plugin-sharp/src/__tests__/trace-svg.js +++ /dev/null @@ -1,270 +0,0 @@ -jest.mock(`os`, () => { - const path = require(`path`) - - return { - ...jest.requireActual(`os`), - tmpdir: () => path.join(__dirname, `.cache`), - } -}) - -const path = require(`path`) -const fs = require(`fs-extra`) - -const traceSVGHelpers = require(`../trace-svg`) - -const notMemoizedtraceSVG = jest.spyOn(traceSVGHelpers, `notMemoizedtraceSVG`) -const notMemoizedPrepareTraceSVGInputFile = jest.spyOn( - traceSVGHelpers, - `notMemoizedPrepareTraceSVGInputFile` -) -// note that we started spying on not memoized functions first -// now we recreate memoized functions that will use function we just started -// spying on -traceSVGHelpers.createMemoizedFunctions() -const memoizedTraceSVG = jest.spyOn(traceSVGHelpers, `memoizedTraceSVG`) -const memoizedPrepareTraceSVGInputFile = jest.spyOn( - traceSVGHelpers, - `memoizedPrepareTraceSVGInputFile` -) - -const { traceSVG } = require(`../`) - -function getFileObject(absolutePath, name = path.parse(absolutePath).name) { - return { - id: `${absolutePath} absPath of file`, - name: name, - absolutePath, - extension: `png`, - internal: { - contentDigest: `2022-01-13T13:27:56.654Z`, - }, - } -} - -describe(`traceSVG memoization`, () => { - const file = getFileObject(path.join(__dirname, `images/test.png`)) - const differentFile = getFileObject( - path.join(__dirname, `images/144-density.png`) - ) - differentFile.internal.contentDigest = `4321` - - beforeAll(async () => { - await fs.ensureDir(path.join(__dirname, `.cache`)) - }) - - afterAll(async () => { - await fs.remove(path.join(__dirname, `.cache`)) - }) - - beforeEach(() => { - traceSVGHelpers.clearMemoizeCaches() - memoizedTraceSVG.mockClear() - notMemoizedtraceSVG.mockClear() - memoizedPrepareTraceSVGInputFile.mockClear() - notMemoizedPrepareTraceSVGInputFile.mockClear() - }) - - it(`Baseline`, async () => { - await traceSVG({ - file, - }) - - expect(memoizedTraceSVG).toBeCalledTimes(1) - expect(notMemoizedtraceSVG).toBeCalledTimes(1) - expect(memoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - expect(notMemoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - }) - - it(`should memoizing results for same args`, async () => { - await traceSVG({ - file, - }) - - await traceSVG({ - file, - }) - - expect(memoizedTraceSVG).toBeCalledTimes(2) - expect(notMemoizedtraceSVG).toBeCalledTimes(1) - expect(memoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - expect(notMemoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - }) - - it( - `should call functions with same input file when params change`, - async () => { - await traceSVG({ - file, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - await traceSVG({ - file, - args: { - color: `blue`, - }, - fileArgs: { - width: 400, - }, - }) - await traceSVG({ - file, - args: { - color: `red`, - }, - fileArgs: { - width: 200, - }, - }) - await traceSVG({ - file, - args: { - color: `blue`, - }, - fileArgs: { - width: 200, - }, - }) - await traceSVG({ - file: differentFile, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - - expect(memoizedTraceSVG).toBeCalledTimes(5) - expect(notMemoizedtraceSVG).toBeCalledTimes(5) - expect(memoizedPrepareTraceSVGInputFile).toBeCalledTimes(5) - // trace svg should be actually created just 3 times - // because it's affected just by `fileArgs`, and not `args` - // this makes sure we don't try to write to same input file multiple times - expect(notMemoizedPrepareTraceSVGInputFile).toBeCalledTimes(3) - expect(notMemoizedPrepareTraceSVGInputFile).toHaveBeenNthCalledWith( - 1, - expect.objectContaining({ - file, - options: expect.objectContaining({ - width: 400, - }), - }) - ) - expect(notMemoizedPrepareTraceSVGInputFile).toHaveBeenNthCalledWith( - 2, - expect.objectContaining({ - file, - options: expect.objectContaining({ - width: 200, - }), - }) - ) - expect(notMemoizedPrepareTraceSVGInputFile).toHaveBeenNthCalledWith( - 3, - expect.objectContaining({ - file: differentFile, - options: expect.objectContaining({ - width: 400, - }), - }) - ) - - const usedTmpFilePaths = - notMemoizedPrepareTraceSVGInputFile.mock.calls.map( - args => args[0].tmpFilePath - ) - - // tmpFilePath was always unique - expect(usedTmpFilePaths.length).toBe(new Set(usedTmpFilePaths).size) - }, - 10 * 1000 - ) - - it(`Use memoized results for file copies`, async () => { - const copyPath = path.join(__dirname, `images/test-copy.png`) - await fs.copy(path.join(__dirname, `images/test.png`), copyPath) - - try { - const copyOfFile = getFileObject(copyPath) - await traceSVG({ - file, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - await traceSVG({ - file: copyOfFile, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - } finally { - await fs.remove(copyPath) - } - - expect(memoizedTraceSVG).toBeCalledTimes(2) - expect(notMemoizedtraceSVG).toBeCalledTimes(1) - expect(memoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - expect(notMemoizedPrepareTraceSVGInputFile).toBeCalledTimes(1) - }) - - it(`should work with long filenames`, async () => { - const copyPath = path.join( - __dirname, - `images/${`a`.repeat(10)} (1) ${`a`.repeat(100)}.png` - ) - await fs.copy(path.join(__dirname, `images/test.png`), copyPath) - expect.assertions(1) - - try { - const copyOfFile = getFileObject(copyPath) - await traceSVG({ - file: copyOfFile, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - expect(true).toBe(true) - } finally { - await fs.remove(copyPath) - } - }) - - it(`should work with long filenames that end with a dot`, async () => { - const copyPath = path.join(__dirname, `images/test${`.`.repeat(100)}.png`) - await fs.copy(path.join(__dirname, `images/test.png`), copyPath) - expect.assertions(1) - - try { - const copyOfFile = getFileObject(copyPath) - await traceSVG({ - file: copyOfFile, - args: { - color: `red`, - }, - fileArgs: { - width: 400, - }, - }) - expect(true).toBe(true) - } catch (err) { - await fs.remove(copyPath) - } finally { - await fs.remove(copyPath) - } - }) -}) diff --git a/packages/gatsby-plugin-sharp/src/image-data.ts b/packages/gatsby-plugin-sharp/src/image-data.ts index a6c34cb11ea02..81364e3cd0e7e 100644 --- a/packages/gatsby-plugin-sharp/src/image-data.ts +++ b/packages/gatsby-plugin-sharp/src/image-data.ts @@ -119,6 +119,7 @@ function normalizeFormat(format: string): ImageFormat { return format as ImageFormat } +let didShowTraceSVGRemovalWarning = false export async function generateImageData({ file, args, @@ -128,7 +129,7 @@ export async function generateImageData({ }: IImageDataArgs): Promise { args = mergeDefaults(args) - const { + let { layout = `constrained`, placeholder = `dominantColor`, tracedSVGOptions = {}, @@ -145,6 +146,16 @@ export async function generateImageData({ : DEFAULT_BREAKPOINTS } + if (placeholder === `tracedSVG`) { + if (!didShowTraceSVGRemovalWarning) { + console.warn( + `"TRACED_SVG" placeholder argument value is no longer supported (used in gatsbyImageData processing), falling back to "DOMINANT_COLOR". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarning = true + } + placeholder = `dominantColor` + } + const { fit = `cover`, cropFocus = sharp.strategy.attention, diff --git a/packages/gatsby-plugin-sharp/src/index.js b/packages/gatsby-plugin-sharp/src/index.js index f770efd3f5912..c1fef34709bbc 100644 --- a/packages/gatsby-plugin-sharp/src/index.js +++ b/packages/gatsby-plugin-sharp/src/index.js @@ -15,7 +15,6 @@ const { createTransformObject, removeDefaultValues, } = require(`./plugin-options`) -const { memoizedTraceSVG, notMemoizedtraceSVG } = require(`./trace-svg`) const duotone = require(`./duotone`) const { IMAGE_PROCESSING_JOB_NAME } = require(`./gatsby-worker`) const { getDimensionsAndAspectRatio } = require(`./utils`) @@ -382,26 +381,17 @@ async function base64(arg) { return await memoizedBase64(arg) } +let didShowTraceSVGRemovalWarning = false async function traceSVG(args) { - if (args.cache) { - // Not all transformer plugins are going to provide cache - return await cachifiedProcess(args, generateCacheKey, notMemoizedtraceSVG) + if (!didShowTraceSVGRemovalWarning) { + console.warn( + `traceSVG placeholder generation is no longer supported, falling back to blurred. See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarning = true } - return await memoizedTraceSVG(args) -} -async function getTracedSVG({ file, options, cache, reporter }) { - if (options.generateTracedSVG && options.tracedSVG) { - const tracedSVG = await traceSVG({ - args: options.tracedSVG, - fileArgs: options, - file, - cache, - reporter, - }) - return tracedSVG - } - return undefined + const { src } = await base64(args) + return src } async function stats({ file, reporter }) { @@ -425,6 +415,7 @@ async function stats({ file, reporter }) { } } +let didShowTraceSVGRemovalWarningFluid = false async function fluid({ file, args = {}, reporter, cache }) { const options = healOptions(getPluginOptions(), args, file.extension) @@ -542,8 +533,17 @@ async function fluid({ file, args = {}, reporter, cache }) { reporter, }) + if (options.generateTracedSVG && options.tracedSVG) { + if (!didShowTraceSVGRemovalWarningFluid) { + console.warn( + `tracedSVG placeholder generation for fluid images is no longer supported, falling back to blurred. See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningFluid = true + } + } + let base64Image - if (options.base64) { + if (options.base64 || (options.generateTracedSVG && options.tracedSVG)) { const base64Width = options.base64Width const base64Height = Math.max( 1, @@ -566,8 +566,6 @@ async function fluid({ file, args = {}, reporter, cache }) { base64Image = await base64({ file, args: base64Args, reporter, cache }) } - const tracedSVG = await getTracedSVG({ options, file, cache, reporter }) - // Construct src and srcSet strings. const originalImg = _.maxBy(images, image => image.width).src const fallbackSrc = _.minBy(images, image => @@ -614,7 +612,7 @@ async function fluid({ file, args = {}, reporter, cache }) { `(max-width: ${presentationWidth}px) 100vw, ${presentationWidth}px` return { - base64: base64Image && base64Image.src, + base64: (options.base64 && base64Image && base64Image.src) || undefined, aspectRatio: images[0].aspectRatio, src: fallbackSrc, srcSet, @@ -625,10 +623,16 @@ async function fluid({ file, args = {}, reporter, cache }) { density, presentationWidth, presentationHeight, - tracedSVG, + tracedSVG: + (options.generateTracedSVG && + options.tracedSVG && + base64Image && + base64Image.src) || + undefined, } } +let didShowTraceSVGRemovalWarningFixed = false async function fixed({ file, args = {}, reporter, cache }) { const options = healOptions(getPluginOptions(), args, file.extension) @@ -681,8 +685,17 @@ async function fixed({ file, args = {}, reporter, cache }) { reporter, }) + if (options.generateTracedSVG && options.tracedSVG) { + if (!didShowTraceSVGRemovalWarningFixed) { + console.warn( + `tracedSVG placeholder generation for fixed images is no longer supported, falling back to blurred. See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningFixed = true + } + } + let base64Image - if (options.base64) { + if (options.base64 || (options.generateTracedSVG && options.tracedSVG)) { const base64Width = options.base64Width const base64Height = Math.max( 1, @@ -710,8 +723,6 @@ async function fixed({ file, args = {}, reporter, cache }) { }) } - const tracedSVG = await getTracedSVG({ options, file, reporter, cache }) - const fallbackSrc = images[0].src const srcSet = images .map((image, i) => { @@ -735,14 +746,19 @@ async function fixed({ file, args = {}, reporter, cache }) { const originalName = file.base return { - base64: base64Image && base64Image.src, + base64: (options.base64 && base64Image && base64Image.src) || undefined, aspectRatio: images[0].aspectRatio, width: images[0].width, height: images[0].height, src: fallbackSrc, srcSet, originalName: originalName, - tracedSVG, + tracedSVG: + (options.generateTracedSVG && + options.tracedSVG && + base64Image && + base64Image.src) || + undefined, } } diff --git a/packages/gatsby-plugin-sharp/src/trace-svg.js b/packages/gatsby-plugin-sharp/src/trace-svg.js deleted file mode 100644 index d216b192425a9..0000000000000 --- a/packages/gatsby-plugin-sharp/src/trace-svg.js +++ /dev/null @@ -1,187 +0,0 @@ -const { promisify } = require(`bluebird`) -const fs = require(`fs-extra`) -const _ = require(`lodash`) -const tmpDir = require(`os`).tmpdir() -const path = require(`path`) -const sharp = require(`./safe-sharp`) -const filenamify = require(`filenamify`) -const duotone = require(`./duotone`) -const { getPluginOptions, healOptions } = require(`./plugin-options`) -const { reportError } = require(`./report-error`) -const { - createContentDigest, -} = require(`gatsby-core-utils/create-content-digest`) - -exports.notMemoizedPrepareTraceSVGInputFile = async ({ - file, - options, - tmpFilePath, - reporter, -}) => { - let pipeline - try { - pipeline = sharp() - - if (!options.rotate) { - pipeline.rotate() - } - fs.createReadStream(file.absolutePath).pipe(pipeline) - } catch (err) { - reportError(`Failed to process image ${file.absolutePath}`, err, reporter) - return - } - - pipeline - .resize(options.width, options.height, { - position: options.cropFocus, - }) - .png({ - compressionLevel: options.pngCompressionLevel, - adaptiveFiltering: false, - force: options.toFormat === `png`, - }) - .jpeg({ - quality: options.quality, - progressive: options.jpegProgressive, - force: options.toFormat === `jpg`, - }) - - // grayscale - if (options.grayscale) { - pipeline = pipeline.grayscale() - } - - // rotate - if (options.rotate && options.rotate !== 0) { - pipeline = pipeline.rotate(options.rotate) - } - - // duotone - if (options.duotone) { - pipeline = await duotone(options.duotone, options.toFormat, pipeline) - } - - await new Promise((resolve, reject) => - pipeline.toFile(tmpFilePath, err => { - if (err) { - return reject(err) - } - return resolve() - }) - ) -} - -const optimize = svg => { - const { optimize } = require(`svgo`) - const { data } = optimize(svg, { - multipass: true, - floatPrecision: 0, - plugins: [ - { - name: `preset-default`, - params: { - overrides: { - // disable removeViewBox plugin - removeViewBox: false, - }, - }, - }, - { - name: `addAttributesToSVGElement`, - params: { - attributes: [ - { - preserveAspectRatio: `none`, - }, - ], - }, - }, - ], - }) - return data -} - -exports.notMemoizedtraceSVG = async ({ file, args, fileArgs, reporter }) => { - const options = healOptions( - getPluginOptions(), - { - // use maxWidth/maxHeight as width/height if available - // if width/height is used in fileArgs, the maxWidth/maxHeight - // values will be overritten - ...(fileArgs && fileArgs.maxWidth && fileArgs.maxHeight - ? { - height: fileArgs.maxHeight, - width: fileArgs.maxWidth, - } - : {}), - ...fileArgs, - }, - file.extension - ) - - const optionsHash = createContentDigest(options) - - const tmpFilePath = path.join( - tmpDir, - filenamify(`${file.internal.contentDigest}-${file.name}-${optionsHash}`) + - `.${file.extension}` - ) - - await exports.memoizedPrepareTraceSVGInputFile({ - tmpFilePath, - file, - options, - reporter, - }) - - const svgToMiniDataURI = require(`mini-svg-data-uri`) - const potrace = require(`@gatsbyjs/potrace`) - const trace = promisify(potrace.trace) - - const defaultArgs = { - color: `lightgray`, - optTolerance: 0.4, - turdSize: 100, - turnPolicy: potrace.Potrace.TURNPOLICY_MAJORITY, - } - - const optionsSVG = _.defaults({}, args, defaultArgs) - - // `srcset` attribute rejects URIs with literal spaces - const encodeSpaces = str => str.replace(/ /gi, `%20`) - - return trace(tmpFilePath, optionsSVG) - .then(optimize) - .then(svgToMiniDataURI) - .then(encodeSpaces) -} - -let memoizedPrepareTraceSVGInputFile -let memoizedTraceSVG -const createMemoizedFunctions = () => { - exports.memoizedPrepareTraceSVGInputFile = memoizedPrepareTraceSVGInputFile = - _.memoize( - exports.notMemoizedPrepareTraceSVGInputFile, - ({ tmpFilePath }) => tmpFilePath - ) - - exports.memoizedTraceSVG = memoizedTraceSVG = _.memoize( - exports.notMemoizedtraceSVG, - ({ file, args, fileArgs }) => - `${file.internal.contentDigest}${JSON.stringify(args)}${JSON.stringify( - fileArgs - )}` - ) -} - -// This is very hacky, but memoized function are pretty tricky to spy on -// in tests ;( -createMemoizedFunctions() -exports.createMemoizedFunctions = () => { - createMemoizedFunctions() -} - -exports.clearMemoizeCaches = () => { - memoizedTraceSVG.cache.clear() - memoizedPrepareTraceSVGInputFile.cache.clear() -} diff --git a/packages/gatsby-plugin-utils/package.json b/packages/gatsby-plugin-utils/package.json index 6e7612a80f6ee..9645d0650ab66 100644 --- a/packages/gatsby-plugin-utils/package.json +++ b/packages/gatsby-plugin-utils/package.json @@ -47,7 +47,6 @@ "homepage": "https://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-plugin-utils#readme", "dependencies": { "@babel/runtime": "^7.15.4", - "@gatsbyjs/potrace": "^2.3.0", "fastq": "^1.13.0", "fs-extra": "^10.1.0", "gatsby-core-utils": "^4.2.0-next.0", @@ -55,9 +54,7 @@ "graphql-compose": "^9.0.9", "import-from": "^4.0.0", "joi": "^17.4.2", - "mime": "^3.0.0", - "mini-svg-data-uri": "^1.4.4", - "svgo": "^2.8.0" + "mime": "^3.0.0" }, "devDependencies": { "@babel/cli": "^7.15.4", diff --git a/packages/gatsby-plugin-utils/src/polyfill-remote-file/__tests__/gatsby-image-resolver.ts b/packages/gatsby-plugin-utils/src/polyfill-remote-file/__tests__/gatsby-image-resolver.ts index 2cbcca6ad0ffb..5c065601a1067 100644 --- a/packages/gatsby-plugin-utils/src/polyfill-remote-file/__tests__/gatsby-image-resolver.ts +++ b/packages/gatsby-plugin-utils/src/polyfill-remote-file/__tests__/gatsby-image-resolver.ts @@ -724,7 +724,7 @@ describe(`gatsbyImageData`, () => { `) }) - it(`should generate tracedSVG placeholder`, async () => { + it(`should generate tracedSVG placeholder (fallback to dominant_color)`, async () => { fetchRemoteFile.mockResolvedValueOnce( path.join(__dirname, `__fixtures__`, `dog-portrait.jpg`) ) @@ -745,11 +745,11 @@ describe(`gatsbyImageData`, () => { cacheKey: `1`, directory: expect.stringContaining(cacheDir), }) - expect(fixedResult?.placeholder).toMatchInlineSnapshot(` - Object { - "fallback": "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='20'%20height='33'%20viewBox='0%200%2020%2033'%3e%3cpath%20d='M6%201C4%205%204%205%203%203L2%201C0%201%200%205%200%2014s0%209%203%208c4%200%204%200%204-2v-8H6c0-1%202-3%204-3s2%200%202-2l-1-4c0-3%200-3-3-3L6%201'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e", - } - `) + // placeholder doesn't exist, instead backgroundColor is used + expect(fixedResult?.placeholder).not.toBeDefined() + expect(fixedResult?.backgroundColor).toMatchInlineSnapshot( + `"rgb(56,40,40)"` + ) }) it(`should render avif, webp other format in this order`, async () => { diff --git a/packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/gatsby-image-resolver.ts b/packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/gatsby-image-resolver.ts index 495b29005e963..4befd828b67cf 100644 --- a/packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/gatsby-image-resolver.ts +++ b/packages/gatsby-plugin-utils/src/polyfill-remote-file/graphql/gatsby-image-resolver.ts @@ -76,6 +76,7 @@ const GATSBY_SHOULD_TRACK_IMAGE_CDN_URLS = [`true`, `1`].includes( process.env.GATSBY_SHOULD_TRACK_IMAGE_CDN_URLS || `` ) +let didShowTraceSVGRemovalWarning = false export async function gatsbyImageResolver( source: IRemoteFileNode, args: IGatsbyImageDataArgs, @@ -121,6 +122,14 @@ export async function gatsbyImageResolver( if (!args.placeholder) { args.placeholder = PlaceholderType.DOMINANT_COLOR + } else if (args.placeholder === PlaceholderType.TRACED_SVG) { + if (!didShowTraceSVGRemovalWarning) { + console.warn( + `"TRACED_SVG" placeholder argument value is no longer supported (used in gatsbyImage processing), falling back to "DOMINANT_COLOR". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarning = true + } + args.placeholder = PlaceholderType.DOMINANT_COLOR } if (!args.quality) { @@ -305,9 +314,9 @@ export function generateGatsbyImageFieldConfig( defaultValue: enums.placeholder.getField(`DOMINANT_COLOR`).value, description: stripIndent` Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument "backgroundColor" to use a fixed background color.`, }, aspectRatio: { diff --git a/packages/gatsby-plugin-utils/src/polyfill-remote-file/placeholder-handler.ts b/packages/gatsby-plugin-utils/src/polyfill-remote-file/placeholder-handler.ts index f1ac0303349fd..c97cdd2863604 100644 --- a/packages/gatsby-plugin-utils/src/polyfill-remote-file/placeholder-handler.ts +++ b/packages/gatsby-plugin-utils/src/polyfill-remote-file/placeholder-handler.ts @@ -34,6 +34,7 @@ const PLACEHOLDER_TRACED_WIDTH = 200 let tmpDir: string +let didShowTraceSVGRemovalWarning = false const queue = Queue< undefined, { @@ -66,6 +67,19 @@ const queue = Queue< httpHeaders, }) + if (type === PlaceholderType.TRACED_SVG) { + if (!didShowTraceSVGRemovalWarning) { + // we should not hit this code path, field resolver should fallback earlier, this is just in-case. + // also this falls back to BLURRED because the shape is compatible. DOMINANT_COLOR is not compatible + // and fallback to DOMINANT_COLOR need to happen very early on and not when already generating value + console.warn( + `"TRACED_SVG" placeholder is no longer supported, falling back to "BLURRED". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarning = true + } + type = PlaceholderType.BLURRED + } + switch (type) { case PlaceholderType.BLURRED: { let buffer: Buffer @@ -99,76 +113,6 @@ const queue = Queue< : `rgba(0,0,0,0)` ) } - case PlaceholderType.TRACED_SVG: { - let buffer: Buffer - - try { - const fileStream = createReadStream(filePath) - const pipeline = sharp() - fileStream.pipe(pipeline) - buffer = await pipeline - .resize( - PLACEHOLDER_BASE64_WIDTH, - Math.ceil(PLACEHOLDER_BASE64_WIDTH / (width / height)) - ) - .toBuffer() - } catch (err) { - buffer = await readFile(filePath) - } - - const [{ trace, Potrace }, { optimize }, { default: svgToMiniDataURI }] = - await Promise.all([ - import(`@gatsbyjs/potrace`), - import(`svgo`), - import(`mini-svg-data-uri`), - ]) - - trace( - buffer, - { - color: `lightgray`, - optTolerance: 0.4, - turdSize: 100, - turnPolicy: Potrace.TURNPOLICY_MAJORITY, - }, - async (err, svg) => { - if (err) { - return cb(err) - } - - try { - const { data } = await optimize(svg, { - multipass: true, - floatPrecision: 0, - plugins: [ - { - name: `preset-default`, - params: { - overrides: { - // customize default plugin options - removeViewBox: false, - - // or disable plugins - addAttributesToSVGElement: { - attributes: [ - { - preserveAspectRatio: `none`, - }, - ], - }, - }, - }, - }, - ], - }) - - return cb(null, svgToMiniDataURI(data).replace(/ /gi, `%20`)) - } catch (err) { - return cb(err) - } - } - ) - } } }, QUEUE_CONCURRENCY) diff --git a/packages/gatsby-remark-images/package.json b/packages/gatsby-remark-images/package.json index 12830d574d837..59c8fa1b996fd 100644 --- a/packages/gatsby-remark-images/package.json +++ b/packages/gatsby-remark-images/package.json @@ -8,7 +8,6 @@ }, "dependencies": { "@babel/runtime": "^7.15.4", - "@gatsbyjs/potrace": "^2.3.0", "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.10", "gatsby-core-utils": "^4.2.0-next.0", diff --git a/packages/gatsby-remark-images/src/__tests__/__snapshots__/index.js.snap b/packages/gatsby-remark-images/src/__tests__/__snapshots__/index.js.snap index 138fbf30a3090..af0871b2661c1 100644 --- a/packages/gatsby-remark-images/src/__tests__/__snapshots__/index.js.snap +++ b/packages/gatsby-remark-images/src/__tests__/__snapshots__/index.js.snap @@ -124,6 +124,37 @@ exports[`disableBgImageOnAlpha does not disable background image on transparent " `; +exports[`it doesn't use tracedSVG placeholder (deprecated and fallback to base64) 1`] = ` +" + + + \\"image\\" + + " +`; + exports[`it handles goofy nesting properly 1`] = ` "" `; -exports[`it uses tracedSVG placeholder when enabled 1`] = ` -" - - - \\"image\\" - - " -`; - exports[`markdownCaptions display title in markdown as caption when showCaptions === true && markdownCaptions === true 1`] = ` "
{ + // silence warnings +}) + +beforeEach(() => { + warnSpy.mockClear() +}) describe(`pluginOptionsSchema`, () => { it(`should provide meaningful errors when fields are invalid`, async () => { @@ -70,6 +77,10 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) @@ -161,6 +172,12 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + if (booleanValue) { + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) + } expect(errors).toEqual([]) }) }) @@ -171,7 +188,7 @@ describe(`pluginOptionsSchema`, () => { pluginOptionsSchema, { tracedSVG: { - turnPolicy: Potrace.TURNPOLICY_RIGHT, + turnPolicy: `TURNPOLICY_RIGHT`, turdSize: 50, alphaMax: 0.5, optCurve: false, @@ -185,6 +202,10 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) @@ -193,7 +214,7 @@ describe(`pluginOptionsSchema`, () => { pluginOptionsSchema, { tracedSVG: { - turnPolicy: Potrace.TURNPOLICY_RIGHT, + turnPolicy: `TURNPOLICY_RIGHT`, turdSize: 50, // alphaMax: 0.5, // optCurve: 0.2, @@ -207,6 +228,10 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) @@ -243,16 +268,20 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) it.each([ - Potrace.TURNPOLICY_BLACK, - Potrace.TURNPOLICY_WHITE, - Potrace.TURNPOLICY_LEFT, - Potrace.TURNPOLICY_RIGHT, - Potrace.TURNPOLICY_MINORITY, - Potrace.TURNPOLICY_MAJORITY, + `black`, + `white`, + `left`, + `TURNPOLICY_RIGHT`, + `minority`, + `majority`, ])(`supports setting by policy value (%s)`, async value => { const { isValid, errors } = await testPluginOptionsSchema( pluginOptionsSchema, @@ -262,6 +291,10 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) @@ -288,7 +321,7 @@ describe(`pluginOptionsSchema`, () => { [ `THRESHOLD_AUTO`, { - value: Potrace.THRESHOLD_AUTO, + value: -1, expectedIsValid: true, }, ], @@ -324,6 +357,10 @@ describe(`pluginOptionsSchema`, () => { ) expect(isValid).toBe(true) + + expect(warnSpy).toBeCalledWith( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) expect(errors).toEqual([]) }) diff --git a/packages/gatsby-remark-images/src/__tests__/index.js b/packages/gatsby-remark-images/src/__tests__/index.js index 56c44c095e01e..90cae91aeebcf 100644 --- a/packages/gatsby-remark-images/src/__tests__/index.js +++ b/packages/gatsby-remark-images/src/__tests__/index.js @@ -25,7 +25,6 @@ jest.mock(`gatsby-plugin-sharp`, () => { }) const Remark = require(`remark`) -const { Potrace } = require(`@gatsbyjs/potrace`) const queryString = require(`query-string`) const cheerio = require(`cheerio`) const toHAST = require(`mdast-util-to-hast`) @@ -453,7 +452,7 @@ test(`it transforms images in markdown with query strings`, async () => { expect(node.value).not.toMatch(``) }) -test(`it uses tracedSVG placeholder when enabled`, async () => { +test(`it doesn't use tracedSVG placeholder (deprecated and fallback to base64)`, async () => { const imagePath = `images/my-image.jpeg` const content = ` ![image](./${imagePath}) @@ -469,16 +468,7 @@ test(`it uses tracedSVG placeholder when enabled`, async () => { expect(node.type).toBe(`html`) expect(node.value).toMatchSnapshot() expect(node.value).not.toMatch(``) - expect(mockTraceSVG).toBeCalledTimes(1) - - expect(mockTraceSVG).toBeCalledWith( - expect.objectContaining({ - // fileArgs cannot be left undefined or traceSVG errors - fileArgs: expect.any(Object), - // args containing Potrace constants should be translated to their values - args: { color: Potrace.COLOR_AUTO, turnPolicy: Potrace.TURNPOLICY_LEFT }, - }) - ) + expect(mockTraceSVG).toBeCalledTimes(0) }) describe(`showCaptions`, () => { diff --git a/packages/gatsby-remark-images/src/gatsby-node.js b/packages/gatsby-remark-images/src/gatsby-node.js index 25f9f2f6de9a5..c1157c6e4d574 100644 --- a/packages/gatsby-remark-images/src/gatsby-node.js +++ b/packages/gatsby-remark-images/src/gatsby-node.js @@ -1,5 +1,3 @@ -const { Potrace } = require(`@gatsbyjs/potrace`) - exports.pluginOptionsSchema = function ({ Joi }) { return Joi.object({ maxWidth: Joi.number() @@ -69,30 +67,34 @@ exports.pluginOptionsSchema = function ({ Joi }) { `TURNPOLICY_MINORITY`, `TURNPOLICY_MAJORITY`, // it also allow using actual policy values - Potrace.TURNPOLICY_BLACK, - Potrace.TURNPOLICY_WHITE, - Potrace.TURNPOLICY_LEFT, - Potrace.TURNPOLICY_RIGHT, - Potrace.TURNPOLICY_MINORITY, - Potrace.TURNPOLICY_MAJORITY + `black`, + `white`, + `left`, + `right`, + `minority`, + `majority` ) - .default(Potrace.TURNPOLICY_MAJORITY), + .default(`majority`), turdSize: Joi.number().default(100), alphaMax: Joi.number(), optCurve: Joi.boolean().default(true), optTolerance: Joi.number().default(0.4), threshold: Joi.alternatives() - .try( - Joi.number().min(0).max(255), - Joi.number().valid(Potrace.THRESHOLD_AUTO) - ) - .default(Potrace.THRESHOLD_AUTO), + .try(Joi.number().min(0).max(255), Joi.number().valid(-1)) + .default(-1), blackOnWhite: Joi.boolean().default(true), color: Joi.string().default(`lightgray`), background: Joi.string().default(`transparent`), }) ) - .default(false) + .custom(value => { + if (!!value && !process.env.GATSBY_WORKER_ID) { + console.warn( + `"tracedSVG" plugin option for "gatsby-remark-images" is no longer supported. Blurred placeholder will be used. See https://gatsby.dev/tracesvg-removal/` + ) + } + return undefined + }) .description( `Use traced SVGs for placeholder images instead of the “blur up” effect. Pass true for traced SVGs with the default settings (seen here), or an object of options to override the default. 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 for a full listing and explanation of the available options.` ), diff --git a/packages/gatsby-remark-images/src/index.js b/packages/gatsby-remark-images/src/index.js index 0f07da46b026f..12009f0c13e0e 100644 --- a/packages/gatsby-remark-images/src/index.js +++ b/packages/gatsby-remark-images/src/index.js @@ -347,32 +347,7 @@ module.exports = ( `.trim() } - let placeholderImageData = fluidResult.base64 - - // if options.tracedSVG is enabled generate the traced SVG and use that as the placeholder image - if (options.tracedSVG) { - let args = typeof options.tracedSVG === `object` ? options.tracedSVG : {} - - // Translate Potrace constants (e.g. TURNPOLICY_LEFT, COLOR_AUTO) to the values Potrace expects - const { Potrace } = require(`@gatsbyjs/potrace`) - const argsKeys = Object.keys(args) - args = argsKeys.reduce((result, key) => { - const value = args[key] - result[key] = Potrace.hasOwnProperty(value) ? Potrace[value] : value - return result - }, {}) - - const tracedSVG = await traceSVG({ - file: imageNode, - args, - fileArgs: args, - cache, - reporter, - }) - - // Escape single quotes so the SVG data can be used in inline style attribute with single quotes - placeholderImageData = tracedSVG.replace(/'/g, `\\'`) - } + const placeholderImageData = fluidResult.base64 const ratio = `${(1 / fluidResult.aspectRatio) * 100}%` diff --git a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-plugin-image.js.snap b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-plugin-image.js.snap index 4a949fcad7511..1e57c49704a85 100644 --- a/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-plugin-image.js.snap +++ b/packages/gatsby-source-contentful/src/__tests__/__snapshots__/gatsby-plugin-image.js.snap @@ -57,9 +57,9 @@ https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda } `; -exports[`gatsby-plugin-image defaults via gatsby-plugin-sharp custom placeholder tracedSVG 1`] = ` +exports[`gatsby-plugin-image defaults via gatsby-plugin-sharp custom placeholder tracedSVG (falls back to DOMINANT_COLOR) 1`] = ` Object { - "backgroundColor": undefined, + "backgroundColor": "#080808", "height": 338, "images": Object { "fallback": Object { @@ -80,9 +80,6 @@ https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda ], }, "layout": "constrained", - "placeholder": Object { - "fallback": "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='82'%20viewBox='0%200%20400%2082'%20preserveAspectRatio='none'%3e%3cpath%20d='M27%203C15%208%2010%2013%2010%2019c0%208%209%2011%2015%205%2010-8%2022-8%2032%200%204%204%209%204%2012%201C82%2012%2048-6%2027%203m305%207c-5%203-6%208-6%2029s0%2022%205%2022%205-1%205-16V32h4c4%200%206-2%206-5-1-3-2-3-6-3s-4%200-4-2c0-3%203-6%206-6%204%200%205-2%205-5-1-4-10-4-15-1m-130%205-1%2019v19l3%203c3%203%203%203%209%203l6%201v-4c0-3-1-3-4-4-4-1-5-4-5-13%200-7%201-7%203-7%206%201%209-3%207-7-1-2-2-2-5-2h-5v-4c0-4-1-5-4-5l-4%201m102%200c-2%202-1%2034%200%2038%203%206%207%208%2015%207%205%200%203-8-1-8s-5-2-5-11v-9h4c4%200%206-1%206-4%200-4-2-5-6-5s-4%200-4-3l-1-5h-8m87%200v45l4%201%204-1V15h-8M96%2024c-14%207-15%2027-2%2034%207%204%2019%203%2023-2%201-2%201-2-1-5-3-2-3-2-7-1-10%204-17-3-14-12%202-6%208-9%2014-6%203%201%208-2%208-5%200-4-16-7-21-3m32%200c-15%208-12%2032%204%2036%2015%204%2028-9%2024-24-3-11-17-17-28-12m49-1-5%202c-3%202-3%202-4%200s-2-2-4-2l-3%201-1%2015c-1%2019-1%2021%205%2021h4V49c1-13%201-14%205-17%204-2%206-1%2010%201%202%203%202%203%203%2015l1%2012h8V46c0-15-1-17-7-21-3-2-9-3-12-2m55%201c-15%207-15%2029%200%2035%207%203%2018%202%2023-2l2-2-2-3c-3-2-3-2-6-1-6%202-13%201-16-1-4-5-3-5%2012-5h14v-5c0-14-14-22-27-16m31%200-1%2018v17l2%201c6%202%208%200%208-12%200-13%202-16%2010-16%205%200%207%203%207%2016l1%2011c2%202%205%202%207%201%203-2%203-25-1-30-4-7-14-9-21-5-4%202-4%202-4%200-1-2-6-3-8-1m87%200c-3%202-2%2024%200%2029%204%208%2014%2010%2022%206l4-1c0%202%205%204%207%202%201-1%202-3%202-18V25l-4-1c-6%200-6%201-6%2013s-2%2015-9%2015-8-3-8-16c0-10%200-11-2-12h-6M131%2034c-6%205-3%2016%204%2018%209%201%2015-8%2010-16-3-6-9-7-14-2M14%2055c-9%205-5%2015%208%2022%2016%208%2034%205%2046-6%2010-9-1-22-11-13-10%208-22%208-31%200-4-4-9-5-12-3'%20fill='%23639'%20fill-rule='evenodd'/%3e%3c/svg%3e", - }, "width": "1646", } `; @@ -333,9 +330,9 @@ https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda } `; -exports[`gatsby-plugin-image query arguments placeholder traced svg 1`] = ` +exports[`gatsby-plugin-image query arguments placeholder traced svg (falls back to DOMINANT_COLOR) 1`] = ` Object { - "backgroundColor": undefined, + "backgroundColor": "#080808", "height": 338, "images": Object { "fallback": Object { @@ -356,9 +353,6 @@ https://images.ctfassets.net:443/k8iqpp6u0ior/3ljGfnpegOnBTFGhV07iC1/94257340bda ], }, "layout": "constrained", - "placeholder": Object { - "fallback": "data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20width='400'%20height='82'%20viewBox='0%200%20400%2082'%20preserveAspectRatio='none'%3e%3cpath%20d='M27%203C15%208%2010%2013%2010%2019c0%208%209%2011%2015%205%2010-8%2022-8%2032%200%204%204%209%204%2012%201C82%2012%2048-6%2027%203m305%207c-5%203-6%208-6%2029s0%2022%205%2022%205-1%205-16V32h4c4%200%206-2%206-5-1-3-2-3-6-3s-4%200-4-2c0-3%203-6%206-6%204%200%205-2%205-5-1-4-10-4-15-1m-130%205-1%2019v19l3%203c3%203%203%203%209%203l6%201v-4c0-3-1-3-4-4-4-1-5-4-5-13%200-7%201-7%203-7%206%201%209-3%207-7-1-2-2-2-5-2h-5v-4c0-4-1-5-4-5l-4%201m102%200c-2%202-1%2034%200%2038%203%206%207%208%2015%207%205%200%203-8-1-8s-5-2-5-11v-9h4c4%200%206-1%206-4%200-4-2-5-6-5s-4%200-4-3l-1-5h-8m87%200v45l4%201%204-1V15h-8M96%2024c-14%207-15%2027-2%2034%207%204%2019%203%2023-2%201-2%201-2-1-5-3-2-3-2-7-1-10%204-17-3-14-12%202-6%208-9%2014-6%203%201%208-2%208-5%200-4-16-7-21-3m32%200c-15%208-12%2032%204%2036%2015%204%2028-9%2024-24-3-11-17-17-28-12m49-1-5%202c-3%202-3%202-4%200s-2-2-4-2l-3%201-1%2015c-1%2019-1%2021%205%2021h4V49c1-13%201-14%205-17%204-2%206-1%2010%201%202%203%202%203%203%2015l1%2012h8V46c0-15-1-17-7-21-3-2-9-3-12-2m55%201c-15%207-15%2029%200%2035%207%203%2018%202%2023-2l2-2-2-3c-3-2-3-2-6-1-6%202-13%201-16-1-4-5-3-5%2012-5h14v-5c0-14-14-22-27-16m31%200-1%2018v17l2%201c6%202%208%200%208-12%200-13%202-16%2010-16%205%200%207%203%207%2016l1%2011c2%202%205%202%207%201%203-2%203-25-1-30-4-7-14-9-21-5-4%202-4%202-4%200-1-2-6-3-8-1m87%200c-3%202-2%2024%200%2029%204%208%2014%2010%2022%206l4-1c0%202%205%204%207%202%201-1%202-3%202-18V25l-4-1c-6%200-6%201-6%2013s-2%2015-9%2015-8-3-8-16c0-10%200-11-2-12h-6M131%2034c-6%205-3%2016%204%2018%209%201%2015-8%2010-16-3-6-9-7-14-2M14%2055c-9%205-5%2015%208%2022%2016%208%2034%205%2046-6%2010-9-1-22-11-13-10%208-22%208-31%200-4-4-9-5-12-3'%20fill='%23d3d3d3'%20fill-rule='evenodd'/%3e%3c/svg%3e", - }, "width": "1646", } `; diff --git a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js index b60b7139e628d..033ea67336beb 100644 --- a/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/__tests__/gatsby-plugin-image.js @@ -242,7 +242,7 @@ describe(`gatsby-plugin-image`, () => { expect(resp.placeholder.fallback).toMatch(/^data:image\/png;base64,.+/) expect(resp).toMatchSnapshot() }) - it(`placeholder traced svg`, async () => { + it(`placeholder traced svg (falls back to DOMINANT_COLOR)`, async () => { const resp = await extendedNodeType.gatsbyImageData.resolve( exampleImage, // @ts-ignore @@ -252,9 +252,8 @@ describe(`gatsby-plugin-image`, () => { null, null ) - expect(resp.backgroundColor).toEqual(undefined) - expect(resp.placeholder.fallback).toMatch(/^data:image\/svg\+xml,.+/) - expect(resp.placeholder.fallback).toContain(`fill='%23d3d3d3'`) + expect(resp.backgroundColor).toEqual(`#080808`) + expect(resp.placeholder).not.toBeDefined() expect(resp).toMatchSnapshot() }) }) @@ -302,7 +301,7 @@ describe(`gatsby-plugin-image`, () => { expect(resp).toMatchSnapshot() }) - it(`custom placeholder tracedSVG`, async () => { + it(`custom placeholder tracedSVG (falls back to DOMINANT_COLOR)`, async () => { setPluginOptions({ defaults: { placeholder: `tracedSVG`, @@ -319,8 +318,8 @@ describe(`gatsby-plugin-image`, () => { null, null ) - expect(resp.placeholder.fallback).toMatch(/^data:image\/svg\+xml,.+/) - expect(resp.placeholder.fallback).toContain(`fill='%23639'`) + expect(resp.backgroundColor).toEqual(`#080808`) + expect(resp.placeholder).not.toBeDefined() expect(resp).toMatchSnapshot() }) diff --git a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js index d642aff4ffc7a..963df00d8b013 100644 --- a/packages/gatsby-source-contentful/src/gatsby-plugin-image.js +++ b/packages/gatsby-source-contentful/src/gatsby-plugin-image.js @@ -252,6 +252,7 @@ export function generateImageSource( return { width, height, format: toFormat, src } } +let didShowTraceSVGRemovalWarning = false export async function resolveGatsbyImageData( image, options, @@ -286,6 +287,16 @@ export async function resolveGatsbyImageData( options = doMergeDefaults(options, defaults) + if (options.placeholder === `tracedSVG`) { + if (!didShowTraceSVGRemovalWarning) { + console.warn( + `"TRACED_SVG" placeholder argument value is no longer supported (used in ContentfulAsset.gatsbyImageData processing), falling back to "DOMINANT_COLOR". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarning = true + } + options.placeholder = `dominantColor` + } + const { baseUrl, contentType, width, height } = getBasicImageProps( image, options @@ -336,11 +347,7 @@ export async function resolveGatsbyImageData( } if (options.placeholder === `tracedSVG`) { - placeholderDataURI = await getTracedSVG({ - image, - options, - cache, - }) + console.error(`this shouldn't happen`) } if (placeholderDataURI) { diff --git a/packages/gatsby-source-shopify/__tests__/__snapshots__/create-resolvers.ts.snap b/packages/gatsby-source-shopify/__tests__/__snapshots__/create-resolvers.ts.snap index bf094215a8117..66a9f7a38d9b6 100644 --- a/packages/gatsby-source-shopify/__tests__/__snapshots__/create-resolvers.ts.snap +++ b/packages/gatsby-source-shopify/__tests__/__snapshots__/create-resolvers.ts.snap @@ -106,9 +106,9 @@ Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, 3x, and [0.25, 0.5, 1, 2] }, "placeholder": Object { "description": "Format of generated placeholder image, displayed while the main image loads. -BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) -DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. -TRACED_SVG: a low-resolution traced SVG of the image. +BLURRED: a blurred, low resolution image, encoded as a base64 data URI. +DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). +TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color.", "type": "GatsbyImagePlaceholder", }, @@ -212,9 +212,9 @@ Default is [ 1, 2 ] for fixed images, meaning 1x, 2x, 3x, and [0.25, 0.5, 1, 2] }, "placeholder": Object { "description": "Format of generated placeholder image, displayed while the main image loads. -BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) -DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. -TRACED_SVG: a low-resolution traced SVG of the image. +BLURRED: a blurred, low resolution image, encoded as a base64 data URI. +DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). +TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color.", "type": "GatsbyImagePlaceholder", }, diff --git a/packages/gatsby-transformer-sharp/package.json b/packages/gatsby-transformer-sharp/package.json index b37b040158628..a135363d3c0a5 100644 --- a/packages/gatsby-transformer-sharp/package.json +++ b/packages/gatsby-transformer-sharp/package.json @@ -8,7 +8,6 @@ }, "dependencies": { "@babel/runtime": "^7.15.4", - "@gatsbyjs/potrace": "^2.3.0", "bluebird": "^3.7.2", "common-tags": "^1.8.2", "fs-extra": "^10.1.0", diff --git a/packages/gatsby-transformer-sharp/src/customize-schema.js b/packages/gatsby-transformer-sharp/src/customize-schema.js index 88fdb4ef1e199..f2b09e6e1e58f 100644 --- a/packages/gatsby-transformer-sharp/src/customize-schema.js +++ b/packages/gatsby-transformer-sharp/src/customize-schema.js @@ -14,7 +14,6 @@ const { base64, fluid, fixed, - traceSVG, generateImageData, } = require(`gatsby-plugin-sharp`) const { hasFeature } = require(`gatsby-plugin-utils`) @@ -67,15 +66,7 @@ function toArray(buf) { return arr } -const getTracedSVG = async ({ file, image, fieldArgs, cache, reporter }) => - traceSVG({ - file, - args: { ...fieldArgs.traceSVG }, - fileArgs: fieldArgs, - cache, - reporter, - }) - +let didShowTraceSVGRemovalWarningFixed = false const fixedNodeType = ({ pathPrefix, getNodeAndSavePathDependency, @@ -90,12 +81,15 @@ const fixedNodeType = ({ base64: { type: GraphQLString }, tracedSVG: { type: GraphQLString, - resolve: parent => - getTracedSVG({ - ...parent, - cache, - reporter, - }), + resolve: parent => { + if (!didShowTraceSVGRemovalWarningFixed) { + console.warn( + `"tracedSVG" placeholder field is no longer supported (used in ImageSharp.fixed processing), falling back to "base64". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningFixed = true + } + return parent.base64 + }, }, aspectRatio: { type: GraphQLFloat }, width: { type: new GraphQLNonNull(GraphQLFloat) }, @@ -234,6 +228,7 @@ const fixedNodeType = ({ } } +let didShowTraceSVGRemovalWarningFluid = false const fluidNodeType = ({ pathPrefix, getNodeAndSavePathDependency, @@ -248,12 +243,15 @@ const fluidNodeType = ({ base64: { type: GraphQLString }, tracedSVG: { type: GraphQLString, - resolve: parent => - getTracedSVG({ - ...parent, - cache, - reporter, - }), + resolve: parent => { + if (!didShowTraceSVGRemovalWarningFluid) { + console.warn( + `"tracedSVG" placeholder field is no longer supported (used in ImageSharp.fluid processing), falling back to "base64". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningFluid = true + } + return parent.base64 + }, }, aspectRatio: { type: new GraphQLNonNull(GraphQLFloat) }, src: { type: new GraphQLNonNull(GraphQLString) }, @@ -401,6 +399,7 @@ const fluidNodeType = ({ } } +let didShowTraceSVGRemovalWarningGatsbyImageData = false const imageNodeType = ({ pathPrefix, getNodeAndSavePathDependency, @@ -447,9 +446,9 @@ const imageNodeType = ({ type: ImagePlaceholderType, description: stripIndent` Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set "background" to use a fixed background color.`, }, blurredOptions: { @@ -529,6 +528,17 @@ const imageNodeType = ({ reporter.warn(`Please upgrade gatsby-plugin-sharp`) return null } + + if (fieldArgs?.placeholder === `tracedSVG`) { + if (!didShowTraceSVGRemovalWarningGatsbyImageData) { + console.warn( + `"TRACED_SVG" placeholder argument value is no longer supported (used in ImageSharp.gatsbyImageData processing), falling back to "DOMINANT_COLOR". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningGatsbyImageData = true + } + fieldArgs.placeholder = `dominantColor` + } + const imageData = await generateImageData({ file, args: fieldArgs, @@ -548,6 +558,8 @@ const imageNodeType = ({ */ const inProgressCopy = new Set() +let didShowTraceSVGRemovalWarningResize = false + const createFields = ({ pathPrefix, getNodeAndSavePathDependency, @@ -632,12 +644,19 @@ const createFields = ({ src: { type: GraphQLString }, tracedSVG: { type: GraphQLString, - resolve: parent => - getTracedSVG({ - ...parent, + resolve: async parent => { + if (!didShowTraceSVGRemovalWarningResize) { + console.warn( + `"tracedSVG" placeholder field is no longer supported (used in ImageSharp.resize processing), falling back to "base64". See https://gatsby.dev/tracesvg-removal/` + ) + didShowTraceSVGRemovalWarningResize = true + } + const { src } = await base64({ + file: parent.file, cache, - reporter, - }), + }) + return src + }, }, width: { type: GraphQLInt }, height: { type: GraphQLInt }, diff --git a/packages/gatsby-transformer-sharp/src/types.ts b/packages/gatsby-transformer-sharp/src/types.ts index 9c00f3042eb88..a3f1310ea9473 100644 --- a/packages/gatsby-transformer-sharp/src/types.ts +++ b/packages/gatsby-transformer-sharp/src/types.ts @@ -8,7 +8,6 @@ import { GraphQLNonNull, GraphQLInputFieldConfigMap, } from "gatsby/graphql" -import { Potrace } from "@gatsbyjs/potrace" import type Sharp from "sharp" const sharp: typeof Sharp = require(`./safe-sharp`) @@ -161,12 +160,12 @@ export const DuotoneGradientType = new GraphQLInputObjectType({ export const PotraceTurnPolicyType = new GraphQLEnumType({ name: `PotraceTurnPolicy`, values: { - TURNPOLICY_BLACK: { value: Potrace.TURNPOLICY_BLACK }, - TURNPOLICY_WHITE: { value: Potrace.TURNPOLICY_WHITE }, - TURNPOLICY_LEFT: { value: Potrace.TURNPOLICY_LEFT }, - TURNPOLICY_RIGHT: { value: Potrace.TURNPOLICY_RIGHT }, - TURNPOLICY_MINORITY: { value: Potrace.TURNPOLICY_MINORITY }, - TURNPOLICY_MAJORITY: { value: Potrace.TURNPOLICY_MAJORITY }, + TURNPOLICY_BLACK: { value: `black` }, + TURNPOLICY_WHITE: { value: `white` }, + TURNPOLICY_LEFT: { value: `left` }, + TURNPOLICY_RIGHT: { value: `right` }, + TURNPOLICY_MINORITY: { value: `minority` }, + TURNPOLICY_MAJORITY: { value: `majority` }, }, }) diff --git a/packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap b/packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap index 6e7c067c27b9d..f51d99052d35e 100644 --- a/packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap +++ b/packages/gatsby/src/schema/__tests__/__snapshots__/print.js.snap @@ -122,9 +122,9 @@ interface RemoteFile { \\"\\"\\" Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color. \\"\\"\\" placeholder: RemoteFilePlaceholder = DOMINANT_COLOR @@ -511,9 +511,9 @@ interface RemoteFile { \\"\\"\\" Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color. \\"\\"\\" placeholder: RemoteFilePlaceholder = DOMINANT_COLOR @@ -910,9 +910,9 @@ interface RemoteFile { \\"\\"\\" Format of generated placeholder image, displayed while the main image loads. - BLURRED: a blurred, low resolution image, encoded as a base64 data URI (default) - DOMINANT_COLOR: a solid color, calculated from the dominant color of the image. - TRACED_SVG: a low-resolution traced SVG of the image. + BLURRED: a blurred, low resolution image, encoded as a base64 data URI + DOMINANT_COLOR: a solid color, calculated from the dominant color of the image (default). + TRACED_SVG: deprecated. Will use DOMINANT_COLOR. NONE: no placeholder. Set the argument \\"backgroundColor\\" to use a fixed background color. \\"\\"\\" placeholder: RemoteFilePlaceholder = DOMINANT_COLOR diff --git a/yarn.lock b/yarn.lock index 04da1310a9db3..f7fff14e1aaaf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1638,13 +1638,6 @@ unique-filename "^1.1.1" which "^1.3.1" -"@gatsbyjs/potrace@^2.3.0": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@gatsbyjs/potrace/-/potrace-2.3.0.tgz#0ac22fb56a02ebc64ce55e4666c4b741cbf27377" - integrity sha512-72szhSY/4tPiPPOzq15CG6LW0s9FuWQ86gkLSUvBNoF0s+jsEdRaZmATYNjiY2Skg//EuyPLEqUQnXKXME0szg== - dependencies: - jimp-compact "^0.16.1-2" - "@gatsbyjs/reach-router@^2.0.0-v2.0": version "2.0.0-v2.0.2" resolved "https://registry.yarnpkg.com/@gatsbyjs/reach-router/-/reach-router-2.0.0-v2.0.2.tgz#6b7e4846e4c68113b8e454fd8ea027ffad5a68c8" @@ -14126,11 +14119,6 @@ jest@^27.4.4: import-local "^3.0.2" jest-cli "^27.4.4" -jimp-compact@^0.16.1-2: - version "0.16.1-2" - resolved "https://registry.yarnpkg.com/jimp-compact/-/jimp-compact-0.16.1-2.tgz#a82ff9a5a81f15a4b61b5e2e50fae6a43305e5a9" - integrity sha512-b2A3rRT1TITzqmaO70U2/uunCh43BQVq7BfRwGPkD5xj8/WZsR3sPTy9DENt+dNZGsel3zBEm1UtYegUxjZW7A== - joi@^14.3.1: version "14.3.1" resolved "https://registry.yarnpkg.com/joi/-/joi-14.3.1.tgz#164a262ec0b855466e0c35eea2a885ae8b6c703c" @@ -22330,7 +22318,7 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" -svgo@^2.3.0, svgo@^2.8.0: +svgo@^2.3.0: version "2.8.0" resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24" integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==