Skip to content

Commit f938716

Browse files
gatsbybotTylerBarnespieh
authored
feat(gatsby-source-drupal): Image CDN support (#35265) (#35510)
Co-authored-by: Tyler Barnes <[email protected]> Co-authored-by: Michal Piechowiak <[email protected]>
1 parent 89509ff commit f938716

File tree

7 files changed

+367
-46
lines changed

7 files changed

+367
-46
lines changed

packages/gatsby-source-drupal/README.md

+62
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,68 @@ count in collection queries" `/admin/config/services/jsonapi/extras` as that
4040
[speeds up fetching data from Drupal by around
4141
4x](https://github.com/gatsbyjs/gatsby/pull/32883).
4242

43+
### Gatsby Image CDN
44+
45+
Gatsby has an Image CDN feature which speeds up your build times as well as your frontend performance.
46+
47+
Previously Gatsby would fetch all image files during the Gatsby build process, transform them for frontend performance, and then serve them as static files on the frontend.
48+
With the new Image CDN feature images are lazily processed when users visit the frontend of your site. The first front-end visitor of any image will transform that image and cache it for all other users.
49+
Note that Image CDN works on all hosting platforms, but only speeds up your builds on Gatsby Cloud, as Gatsby Cloud is the most advanced CI/CD and hosting platform for the Gatsby framework.
50+
51+
- [Image CDN blog post](https://www.gatsbyjs.com/blog/image-cdn-lightning-fast-image-processing-for-gatsby-cloud/)
52+
- [What is Image CDN?](https://support.gatsbyjs.com/hc/en-us/articles/4426379634835-What-is-Image-CDN-)
53+
- [How to enable Image CDN on Gatsby Cloud](https://support.gatsbyjs.com/hc/en-us/articles/4426393233171-How-to-Enable-Image-CDN)
54+
55+
#### Querying for Gatsby Image CDN fields
56+
57+
Follow [this guide](https://support.gatsbyjs.com/hc/en-us/articles/4426393233171-How-to-Enable-Image-CDN) to understand how to use the new `gatsbyImage` GraphQL field.
58+
59+
#### Turning off file downloads
60+
61+
When you're using Gatsby Image CDN you no longer need Gatsby to fetch all of the files in your Drupal instance. Turn that off with the following plugin option. This is required for Image CDN to work.
62+
63+
```js
64+
{
65+
resolve: `gatsby-source-drupal`,
66+
options: {
67+
skipFileDownloads: true,
68+
// other plugin options go here
69+
},
70+
},
71+
```
72+
73+
#### Local dev improvements
74+
75+
Using Image CDN also speeds up your local development startup times when running `gatsby develop`. Instead of fetching all files locally, `gatsby develop` has a local Image CDN emulator.
76+
This means Gatsby will only fetch and process the minimal amount of images required to render any page when you visit your Gatsby site at `http://localhost:8000`.
77+
78+
#### Configuring placeholders for Gatsby Images
79+
80+
By default full size images are fetched and scaled down to be used for low quality image placeholders (for lazy loading images on the frontend).
81+
This can make your builds slower than necessary so follow these steps to configure a new smaller placeholder image size in Drupal. This will speed up your builds when using Gatsby Image CDN.
82+
83+
1. Install the [Consumer image styles module](https://www.drupal.org/project/consumer_image_styles)
84+
2. Navigate to "Extend->Web Services" and turn on "Consumer Image Styles" by checking the box and hitting save.
85+
3. Navigate to "Configuration->Image Styles". and add an image style called "Placeholder".
86+
4. Create a new scale effect and set its width and height to 20.
87+
5. If you already have a placeholder style you want to use, you can set the `gatsby-source-drupal` plugin option `placeholderStyleName` as the machine name of your style. \*\* See example option below
88+
6. For each entity that has an image field, navigate into "Configuration->Web Services->JSON:API->JSON:API Resource Overrides->Entity Type->(overwrite/edit)".
89+
7. Click on "advanced" for each image field you have, select "Image Styles (Image Field)" in the dropdown, then select the placeholder image style and save.
90+
8. Go to "Configuration->Web Services->Consumers" and add a default consumer if it doesn't already exist.
91+
9. Edit your default consumer and add the "Placeholder" image style by checking the box in the bottom section and saving.
92+
10. You may need to clear Drupal's cache under "Config->development->clear all caches".
93+
94+
\*\* Example placeholder style plugin option
95+
96+
```js
97+
{
98+
resolve: `gatsby-source-drupal`,
99+
options: {
100+
placeholderStyleName: `custom_placeholder` // default is `placeholder`
101+
}
102+
}
103+
```
104+
43105
### Filters
44106

45107
You can use the `filters` option to limit the data that is retrieved from Drupal. Filters are applied per JSON API collection. You can use any [valid JSON API filter query](https://www.drupal.org/docs/8/modules/jsonapi/filtering). For large data sets this can reduce the build time of your application by allowing Gatsby to skip content you'll never use.

packages/gatsby-source-drupal/package.json

+2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,13 @@
1313
"bluebird": "^3.7.2",
1414
"body-parser": "^1.19.2",
1515
"fastq": "^1.13.0",
16+
"gatsby-plugin-utils": "^3.7.0",
1617
"gatsby-source-filesystem": "^4.13.0",
1718
"got": "^11.8.3",
1819
"http2-wrapper": "^2.1.10",
1920
"lodash": "^4.17.21",
2021
"opentracing": "^0.14.7",
22+
"probe-image-size": "^7.2.3",
2123
"tiny-async-pool": "^1.3.0",
2224
"url-join": "^4.0.1"
2325
},

packages/gatsby-source-drupal/src/__tests__/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,7 @@ describe(`gatsby-source-drupal`, () => {
693693
{ baseUrl }
694694
)
695695

696-
expect(reporter.warn).toHaveBeenCalledTimes(1)
696+
expect(reporter.warn).toHaveBeenCalledTimes(2)
697697
expect(reporter.activityTimer).toHaveBeenCalledTimes(1)
698698
expect(reporter.activityTimer).toHaveBeenNthCalledWith(
699699
1,

packages/gatsby-source-drupal/src/gatsby-node.js

+69-9
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,21 @@ import HttpAgent from "agentkeepalive"
66
const opentracing = require(`opentracing`)
77
const { SemanticAttributes } = require(`@opentelemetry/semantic-conventions`)
88

9+
const {
10+
polyfillImageServiceDevRoutes,
11+
addRemoteFilePolyfillInterface,
12+
} = require(`gatsby-plugin-utils/polyfill-remote-file`)
13+
914
const { HttpsAgent } = HttpAgent
1015

1116
const { setOptions, getOptions } = require(`./plugin-options`)
1217

13-
const { nodeFromData, downloadFile, isFileNode } = require(`./normalize`)
18+
const {
19+
nodeFromData,
20+
downloadFile,
21+
isFileNode,
22+
imageCDNState,
23+
} = require(`./normalize`)
1424
const {
1525
initRefsLookups,
1626
storeRefsLookups,
@@ -19,6 +29,7 @@ const {
1929
createNodeIfItDoesNotExist,
2030
handleDeletedNode,
2131
drupalCreateNodeManifest,
32+
getExtendedFileNodeData,
2233
} = require(`./utils`)
2334

2435
const agent = {
@@ -377,7 +388,7 @@ ${JSON.stringify(webhookBody, null, 4)}`
377388
nodesToUpdate = [nodeSyncData.data]
378389
}
379390
for (const nodeToUpdate of nodesToUpdate) {
380-
createNodeIfItDoesNotExist({
391+
await createNodeIfItDoesNotExist({
381392
nodeToUpdate,
382393
actions,
383394
createNodeId,
@@ -640,21 +651,47 @@ ${JSON.stringify(webhookBody, null, 4)}`
640651
createNodesSpan.setTag(`sourceNodes.fetch.type`, `full`)
641652

642653
const nodes = new Map()
654+
const fileNodesExtendedData = getExtendedFileNodeData(allData)
643655

644656
// first pass - create basic nodes
645-
_.each(allData, contentType => {
646-
if (!contentType) return
647-
_.each(contentType.data, datum => {
648-
if (!datum) return
649-
const node = nodeFromData(datum, createNodeId, entityReferenceRevisions)
657+
for (const contentType of allData) {
658+
if (!contentType) {
659+
continue
660+
}
661+
662+
await asyncPool(concurrentFileRequests, contentType.data, async datum => {
663+
if (!datum) {
664+
return
665+
}
666+
667+
const node = await nodeFromData(
668+
datum,
669+
createNodeId,
670+
entityReferenceRevisions,
671+
pluginOptions,
672+
fileNodesExtendedData,
673+
reporter
674+
)
675+
650676
drupalCreateNodeManifest({
651677
attributes: datum?.attributes,
652678
gatsbyNode: node,
653679
unstable_createNodeManifest,
654680
})
681+
655682
nodes.set(node.id, node)
656683
})
657-
})
684+
}
685+
686+
if (
687+
!imageCDNState.foundPlaceholderStyle &&
688+
!imageCDNState.hasLoggedNoPlaceholderStyle
689+
) {
690+
imageCDNState.hasLoggedNoPlaceholderStyle = true
691+
reporter.warn(
692+
`[gatsby-source-drupal]\nNo Gatsby Image CDN placeholder style found. Please ensure that you have a placeholder style in your Drupal site for the fastest builds. See the docs for more info on gatsby-source-drupal Image CDN support:\n\nhttps://github.com/gatsbyjs/gatsby/tree/master/packages/gatsby-source-drupal#readme`
693+
)
694+
}
658695

659696
createNodesSpan.setTag(`sourceNodes.createNodes.count`, nodes.size)
660697

@@ -665,6 +702,7 @@ ${JSON.stringify(webhookBody, null, 4)}`
665702
mutateNode: true,
666703
createNodeId,
667704
entityReferenceRevisions,
705+
fileNodesExtendedData,
668706
})
669707
})
670708

@@ -716,7 +754,6 @@ ${JSON.stringify(webhookBody, null, 4)}`
716754

717755
createNodesSpan.finish()
718756
await storeRefsLookups({ cache, getNodes })
719-
return
720757
}
721758

722759
// This is maintained for legacy reasons and will eventually be removed.
@@ -813,3 +850,26 @@ exports.pluginOptionsSchema = ({ Joi }) =>
813850
nonTranslatableEntities: Joi.array().items(Joi.string()).required(),
814851
}),
815852
})
853+
854+
exports.onCreateDevServer = async ({ app }) => {
855+
// this makes the gatsby develop image CDN emulator work on earlier versions of Gatsby.
856+
polyfillImageServiceDevRoutes(app)
857+
}
858+
859+
exports.createSchemaCustomization = ({ actions, schema }) => {
860+
actions.createTypes([
861+
// polyfill so image CDN works on older versions of Gatsby
862+
addRemoteFilePolyfillInterface(
863+
// this type is merged in with the inferred file__file type, adding Image CDN support via the gatsbyImage GraphQL field. The `RemoteFile` interface as well as the polyfill above are what add the gatsbyImage field.
864+
schema.buildObjectType({
865+
name: `file__file`,
866+
fields: {},
867+
interfaces: [`Node`, `RemoteFile`],
868+
}),
869+
{
870+
schema,
871+
actions,
872+
}
873+
),
874+
])
875+
}

0 commit comments

Comments
 (0)