generated from netlify/build-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 19
feat: netlify Image cdn support #710
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
Merged
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
f242cc9
feat: image cdn support
kathmbeck 42765a9
fix: package-lock
kathmbeck fb24aff
Merge remote-tracking branch 'origin/main' into image-cdn-support
kathmbeck 3d7adbd
fix: lint
kathmbeck 5139347
fix: dependencies
kathmbeck 538dd98
feat: testing
kathmbeck c48feda
fix: update function
kathmbeck d275cb2
fix: temp remove function
kathmbeck 1c1b10c
fix: reorder redirects
kathmbeck 693ed8f
feat: base url encoded paths
kathmbeck f220bbe
fix: eslint
kathmbeck f008de8
Merge branch 'main' into image-cdn-support
kathmbeck f565c7a
fix: update redirect
kathmbeck 8a89b21
Merge branch 'image-cdn-support' of https://github.com/netlify/netlif…
kathmbeck 940f490
fix: error handling
kathmbeck 3fa9d05
fix: debug log
kathmbeck 5b9e0de
fix: path match
kathmbeck a7f95ac
fix: more tweaks
kathmbeck 6ad89ad
fix: split
kathmbeck 01a1d3f
fix: url param
kathmbeck 03b2d66
fix: /functions
kathmbeck 0055290
fix: param pattern
kathmbeck 5688b39
fix: properly unencode args
kathmbeck 7c0ff3b
fix: use force for redirects
kathmbeck bfec59a
fix: generate __image lambda only if NETLIFY_IMAGE_CDN is set
pieh 4041e0d
chore: drop dev/debug logs, skip unnecesary awaits
pieh 4f6a19e
feat: apply caching headers
pieh 3ad83e2
fix: add regular cache-control too
pieh dda27f6
Merge remote-tracking branch 'origin/main' into image-cdn-support
pieh aed8e72
chore: use Netlify Image CDN in v5 demo as well
pieh b799256
chore: update image-cdn docs
pieh 5d0d252
Merge remote-tracking branch 'origin/main' into image-cdn-support
pieh eaabdd3
fix: use force for all redirects
kathmbeck 83968a6
fix: update docs
kathmbeck f060fb6
docs: adjust wording for for contentful and drupal to match with word…
pieh d0bfba6
Update docs/image-cdn.md
kathmbeck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
[build] | ||
command = "npm run build" | ||
publish = "public/" | ||
environment = { GATSBY_CLOUD_IMAGE_CDN = "true" } | ||
environment = { NETLIFY_IMAGE_CDN = "true" } | ||
ignore = "if [ $CACHED_COMMIT_REF == $COMMIT_REF ]; then (exit 1); else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ..; fi;" | ||
|
||
[[plugins]] | ||
package = "../plugin/src/index.ts" | ||
|
||
[[plugins]] | ||
package = "@netlify/plugin-local-install-core" | ||
|
||
[images] | ||
remote_images = ['https://images.unsplash.com/*'] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
[build] | ||
command = "npm run build" | ||
publish = "public/" | ||
environment = { GATSBY_CLOUD_IMAGE_CDN = "true" } | ||
environment = { NETLIFY_IMAGE_CDN = "true" } | ||
ignore = "if [ $CACHED_COMMIT_REF == $COMMIT_REF ]; then (exit 1); else git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ..; fi;" | ||
|
||
[[plugins]] | ||
package = "../plugin/src/index.ts" | ||
|
||
[[plugins]] | ||
package = "@netlify/plugin-local-install-core" | ||
|
||
[images] | ||
remote_images = ['https://images.unsplash.com/*'] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,51 +1,73 @@ | ||
# Gatsby Image CDN on Netlify | ||
|
||
Gatsby Image CDN is a new feature available in the prerelease version of Gatsby. | ||
Instead of downloading and processing images at build time, it defers processing | ||
until request time. This can greatly improve build times for sites with remote | ||
images, such as those that use a CMS. Netlify includes full support for Image | ||
CDN, on all plans. | ||
|
||
When using the image CDN, Gatsby generates URLs of the form | ||
`/_gatsby/image/...`. On Netlify, these are served by a | ||
[builder function](https://docs.netlify.com/configure-builds/on-demand-builders/), | ||
powered by [sharp](https://sharp.pixelplumbing.com/) and Nuxt's | ||
[ipx image server](https://github.com/unjs/ipx/). It supports all image formats | ||
supported by Gatsby, including AVIF and WebP. | ||
|
||
On first load there will be a one-time delay while the image is resized, but | ||
subsequent requests will be super-fast as they are served from the edge cache. | ||
Gatsby Image CDN is a feature available since Gatsby v4.10.0. Instead of | ||
downloading and processing images at build time, it defers processing until | ||
request time. This can greatly improve build times for sites with remote images, | ||
such as those that use a CMS. Netlify includes full support for Image CDN, on | ||
all plans. | ||
|
||
## Enabling the Image CDN | ||
|
||
To enable the Image CDN during the beta period, you should set the environment | ||
variable `GATSBY_CLOUD_IMAGE_CDN` to `true`. | ||
To enable the Image CDN, you should set the environment variable | ||
`NETLIFY_IMAGE_CDN` to `true`. You will also need to declare allowed image URL | ||
patterns in `netlify.toml`: | ||
|
||
Image CDN currently requires the beta version of Gatsby. This can be installed | ||
using the `next` tag: | ||
```toml | ||
kathmbeck marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[build.environment] | ||
NETLIFY_IMAGE_CDN = "true" | ||
|
||
```shell | ||
npm install gatsby@next gatsby-plugin-image@next gatsby-plugin-sharp@next gatsby-transformer-sharp@next | ||
[images] | ||
remote_images = [ | ||
'https://example1.com/*', | ||
'https://example2.com/*' | ||
] | ||
``` | ||
|
||
Currently Image CDN supports Contentful and WordPress, and these source plugins | ||
should also be installed using the `next` tag: | ||
Exact URL patterns to use will depend on CMS you use and possibly your | ||
configuration of it. | ||
|
||
```shell | ||
npm install gatsby-source-wordpress@next | ||
``` | ||
- `gatsby-source-contentful`: | ||
|
||
or | ||
```toml | ||
[images] | ||
remote_images = [ | ||
# <your-contentful-space-id> is specified in the `spaceId` option for the | ||
# gatsby-source-contentful plugin in your gatsby-config file. | ||
"https://images.ctfassets.net/<your-contentful-space-id>/*" | ||
] | ||
``` | ||
|
||
```shell | ||
npm install gatsby-source-contentful@next | ||
``` | ||
- `gatsby-source-drupal`: | ||
|
||
```toml | ||
[images] | ||
remote_images = [ | ||
# <your-drupal-base-url> is speciafied in the `baseUrl` option for the | ||
# gatsby-source-drupal plugin in your gatsby-config file. | ||
"<your-drupal-base-url>/*" | ||
] | ||
``` | ||
|
||
- `gatsby-source-wordpress`: | ||
|
||
```toml | ||
[images] | ||
remote_images = [ | ||
# <your-wordpress-url> is specified in the `url` option for the | ||
# gatsby-source-wordpress plugin in your gatsby-config file. | ||
# There is no need to include `/graphql in the path here` | ||
"<your-wordpress-url>/*" | ||
] | ||
``` | ||
|
||
Gatsby will be adding support to more source plugins during the beta period. | ||
These should work automatically as soon as they are added. | ||
Above examples are the most likely ones to be needed. However if you configure | ||
your CMS to host assets on different domain or path, you might need to adjust | ||
the patterns accordingly. | ||
|
||
## Using the Image CDN | ||
## How it works | ||
|
||
Your GraphQL queries will need updating to use the image CDN. The details vary | ||
depending on the source plugin. For more details see | ||
[the Gatsby docs](https://support.gatsbyjs.com/hc/en-us/articles/4522338898579) | ||
When using the Image CDN, Gatsby generates URLs of the form | ||
`/_gatsby/image/...`. On Netlify, these are served by a function that translates | ||
Gatsby Image CDN URLs into Netlify Image CDN compatible URL of the form | ||
`/.netlify/images/...`. For more information about Netlify Image CDN, | ||
documentation can be found [here](https://docs.netlify.com/image-cdn/overview). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import { Buffer } from 'buffer' | ||
|
||
import { Handler } from '@netlify/functions' | ||
|
||
type Event = Parameters<Handler>[0] | ||
|
||
function generateURLFromQueryParamsPath(uParam, cdParam, argsParam) { | ||
try { | ||
const newURL = new URL('.netlify/images', 'https://example.com') | ||
newURL.searchParams.set('url', uParam) | ||
newURL.searchParams.set('cd', cdParam) | ||
|
||
const aParams = new URLSearchParams(argsParam) | ||
aParams.forEach((value, key) => { | ||
newURL.searchParams.set(key, value) | ||
}) | ||
|
||
return newURL.pathname + newURL.search | ||
} catch (error) { | ||
console.error('Error constructing URL:', error) | ||
return null | ||
} | ||
} | ||
|
||
function generateURLFromBase64EncodedPath(path) { | ||
const [, , , encodedUrl, encodedArgs] = path.split('/') | ||
|
||
const decodedUrl = Buffer.from(encodedUrl, 'base64').toString('utf8') | ||
const decodedArgs = Buffer.from(encodedArgs, 'base64').toString('utf8') | ||
|
||
let sourceURL | ||
try { | ||
sourceURL = new URL(decodedUrl) | ||
} catch (error) { | ||
console.error('Decoded string is not a valid URL:', error) | ||
return | ||
} | ||
|
||
const newURL = new URL('.netlify/images', 'https://example.com') | ||
newURL.searchParams.set('url', sourceURL.href) | ||
|
||
const aParams = new URLSearchParams(decodedArgs) | ||
aParams.forEach((value, key) => { | ||
newURL.searchParams.set(key, value) | ||
}) | ||
|
||
return newURL.pathname + newURL.search | ||
} | ||
|
||
// eslint-disable-next-line require-await | ||
export const handler: Handler = async (event: Event) => { | ||
const QUERY_PARAM_PATTERN = | ||
/^\/\.netlify\/functions\/__image\/image_query_compat\/?$/i | ||
|
||
const { pathname } = new URL(event.rawUrl) | ||
const match = pathname.match(QUERY_PARAM_PATTERN) | ||
|
||
let newURL | ||
|
||
if (match) { | ||
// Extract the query parameters | ||
const { | ||
url: uParam, | ||
cd: cdParam, | ||
args: argsParam, | ||
} = event.queryStringParameters | ||
|
||
newURL = generateURLFromQueryParamsPath(uParam, cdParam, argsParam) | ||
} else { | ||
newURL = generateURLFromBase64EncodedPath(pathname) | ||
} | ||
|
||
const cachingHeaders = { | ||
'Cache-Control': 'public,max-age=31536000,immutable', | ||
'Netlify-CDN-Cache-Control': 'public,max-age=31536000,immutable', | ||
'Netlify-Vary': 'query', | ||
} | ||
|
||
return newURL | ||
? { | ||
statusCode: 301, | ||
headers: { | ||
Location: newURL, | ||
...cachingHeaders, | ||
}, | ||
} | ||
: { statusCode: 400, body: 'Invalid request', headers: cachingHeaders } | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.