Skip to content

Commit bc7695d

Browse files
authored
feat: add support for using image config from next.config.js (#518)
1 parent fbdb68c commit bc7695d

File tree

7 files changed

+34
-17
lines changed

7 files changed

+34
-17
lines changed

Diff for: docs/image-handling.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ The Essential Next.js plugin includes a function to generate images for `next/im
44

55
By default, images are returned in the same format as the source image if they are in JPEG, PNG, WebP or AVIF format. If you are only targeting modern browsers and want to live life on the edge, you can [set the environment variable](https://docs.netlify.com/configure-builds/environment-variables/) `FORCE_WEBP_OUTPUT` to `"true"`, and it will return all images in WebP format. This will often lead to significant improvements in file size. However you should not use this if you need to support older browsers, as `next/image` does not support picture tag source fallback and images will appear broken. Check [browser support](https://caniuse.com/webp) to see if you are happy to do this.
66

7-
If you want to use remote images in `next/image`, you will need to add the image domains to an allow list. Setting them in `images.domains` in `next.config.js` is not supported: instead you should set the environment variable `NEXT_IMAGE_ALLOWED_DOMAINS` to a comma-separated list of domains, e.g. `NEXT_IMAGE_ALLOWED_DOMAINS="placekitten.com,unsplash.com"`.
7+
If you want to use remote images in `next/image`, you will need to add the image domains to an allow list. Add the required domains to the `images.domains` array in `next.config.js`.
8+
9+
In previous versions of the Essential Next.js plugin you needed to set the environment variable `NEXT_IMAGE_ALLOWED_DOMAINS` rather than using the Next config file. This is no longer required, and will be removed in a future version.

Diff for: index.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,9 @@ module.exports = {
4949
checkNxConfig({ netlifyConfig, packageJson, nextConfig, failBuild, constants })
5050
}
5151

52-
if (nextConfig.images.domains.length !== 0 && !process.env.NEXT_IMAGE_ALLOWED_DOMAINS) {
52+
if (process.env.NEXT_IMAGE_ALLOWED_DOMAINS) {
5353
console.log(
54-
`Image domains set in next.config.js are ignored.\nPlease set the env variable NEXT_IMAGE_ALLOWED_DOMAINS to "${nextConfig.images.domains.join(
55-
',',
56-
)}" instead`,
54+
`The Essential Next.js plugin now supports reading image domains from your Next config, so using NEXT_IMAGE_ALLOWED_DOMAINS is now deprecated. Please set images.domains in next.config.js instead, and remove the NEXT_IMAGE_ALLOWED_DOMAINS variable.`,
5755
)
5856
}
5957
await restoreCache({ cache: utils.cache, distDir: nextConfig.distDir })

Diff for: src/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const chokidar = require('chokidar')
44
const debounceFn = require('debounce-fn')
55
const execa = require('execa')
66

7+
const getNextConfig = require('../helpers/getNextConfig')
8+
79
const { NETLIFY_PUBLISH_PATH, NETLIFY_FUNCTIONS_PATH, SRC_FILES } = require('./lib/config')
810
const { logTitle } = require('./lib/helpers/logger')
911
const copyNextAssets = require('./lib/steps/copyNextAssets')
@@ -31,7 +33,9 @@ const build = async (functionsPath, publishPath, nextRoot) => {
3133

3234
await setupPages({ functionsPath, publishPath })
3335

34-
setupImageFunction(functionsPath)
36+
const { images } = await getNextConfig()
37+
38+
await setupImageFunction(functionsPath, images)
3539

3640
await setupRedirects(publishPath)
3741

Diff for: src/lib/steps/setupImageFunction.js

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
const { join } = require('path')
22

3-
const { copySync } = require('fs-extra')
3+
const { copyFile, writeJSON, ensureDir } = require('fs-extra')
44

55
const { NEXT_IMAGE_FUNCTION_NAME, TEMPLATES_DIR } = require('../config')
66

77
// Move our next/image function into the correct functions directory
8-
const setupImageFunction = (functionsPath) => {
8+
const setupImageFunction = async (functionsPath, imageconfig = {}) => {
99
const functionName = `${NEXT_IMAGE_FUNCTION_NAME}.js`
10-
const functionDirectory = join(functionsPath, functionName)
10+
const functionDirectory = join(functionsPath, NEXT_IMAGE_FUNCTION_NAME)
1111

12-
copySync(join(TEMPLATES_DIR, 'imageFunction.js'), functionDirectory, {
13-
overwrite: false,
14-
errorOnExist: true,
15-
})
12+
await ensureDir(functionDirectory)
13+
await writeJSON(join(functionDirectory, 'imageconfig.json'), imageconfig)
14+
await copyFile(join(TEMPLATES_DIR, 'imageFunction.js'), join(functionDirectory, functionName))
1615
}
1716

1817
module.exports = setupImageFunction

Diff for: src/lib/templates/imageFunction.js

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const imageType = require('image-type')
55
const isSvg = require('is-svg')
66
const etag = require('etag')
77
const imageSize = require('image-size')
8+
const config = require('./imageconfig.json')
89
// 6MB is hard max Lambda response size
910
const MAX_RESPONSE_SIZE = 6291456
1011

@@ -47,9 +48,14 @@ const handler = async (event) => {
4748
} else {
4849
isRemoteImage = true
4950
// Remote images need to be in the allowlist
50-
const allowedDomains = process.env.NEXT_IMAGE_ALLOWED_DOMAINS
51-
? process.env.NEXT_IMAGE_ALLOWED_DOMAINS.split(',').map((domain) => domain.trim())
52-
: []
51+
let allowedDomains = config.images?.domains || []
52+
53+
if (process.env.NEXT_IMAGE_ALLOWED_DOMAINS) {
54+
console.log('Combining `NEXT_IMAGE_ALLOWED_DOMAINS` with any domains found in `next.config.js`')
55+
allowedDomains = allowedDomains.concat(
56+
process.env.NEXT_IMAGE_ALLOWED_DOMAINS.split(',').map((domain) => domain.trim()),
57+
)
58+
}
5359

5460
if (!allowedDomains.includes(new URL(parsedUrl).hostname)) {
5561
return {

Diff for: src/tests/defaults.test.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,13 @@ describe('next/image', () => {
8686
const functionsDir = join(PROJECT_PATH, 'out_functions')
8787

8888
test('sets up next_image as a function in every project by default', () => {
89-
expect(existsSync(join(functionsDir, 'next_image.js'))).toBe(true)
89+
expect(existsSync(join(functionsDir, 'next_image', 'next_image.js'))).toBe(true)
9090
})
91+
92+
test('injects the image plugin config into the function', () => {
93+
expect(readJsonSync(join(functionsDir, 'next_image', 'imageconfig.json')).domains).toEqual(["placekitten.com"])
94+
})
95+
9196
})
9297

9398
describe('SSG Pages with getStaticProps', () => {

Diff for: src/tests/fixtures/next.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
module.exports = {
22
target: "serverless",
3+
images: {
4+
domains: ["placekitten.com"]
5+
}
36
};

0 commit comments

Comments
 (0)