From 322da872619b38ef210897a171d306dc438347ad Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Wed, 22 Feb 2023 16:45:08 -0500 Subject: [PATCH 01/13] feat: make edge image opt in instead of opt out --- packages/runtime/src/helpers/edge.ts | 198 ++++++++++++++------------- test/index.spec.js | 17 ++- 2 files changed, 120 insertions(+), 95 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 86c081a524..3692eb7b37 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -358,121 +358,131 @@ export const writeEdgeFunctions = async ({ await writeJSON(join(edgeFunctionRoot, 'edge-shared', 'nextConfig.json'), nextConfig) await copy(join(publish, 'prerender-manifest.json'), join(edgeFunctionRoot, 'edge-shared', 'prerender-manifest.json')) - if ( - !destr(process.env.NEXT_DISABLE_EDGE_IMAGES) && - !destr(process.env.NEXT_DISABLE_NETLIFY_EDGE) && - !destr(process.env.DISABLE_IPX) - ) { - console.log( - 'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.', - ) - const edgeFunctionDir = join(edgeFunctionRoot, 'ipx') - await ensureDir(edgeFunctionDir) - await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' }) - await copyFile( - join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'), - join(edgeFunctionDir, 'imageconfig.json'), - ) - manifest.functions.push({ - function: 'ipx', - name: 'next/image handler', - path: '/_next/image*', - }) + // early return if edge is disabled + if (destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) { + return } - if (!destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) { - const rscFunctions = await writeRscDataEdgeFunction({ - prerenderManifest: await loadPrerenderManifest(netlifyConfig), - appPathRoutesManifest: await loadAppPathRoutesManifest(netlifyConfig), - }) - manifest.functions.push(...rscFunctions) + const rscFunctions = await writeRscDataEdgeFunction({ + prerenderManifest: await loadPrerenderManifest(netlifyConfig), + appPathRoutesManifest: await loadAppPathRoutesManifest(netlifyConfig), + }) - const middlewareManifest = await loadMiddlewareManifest(netlifyConfig) - if (!middlewareManifest) { - console.error("Couldn't find the middleware manifest") - return - } + manifest.functions.push(...rscFunctions) - let usesEdge = false + const middlewareManifest = await loadMiddlewareManifest(netlifyConfig) + if (!middlewareManifest) { + console.error("Couldn't find the middleware manifest") + return + } + + let usesEdge = false + + for (const middleware of middlewareManifest.sortedMiddleware) { + usesEdge = true + const edgeFunctionDefinition = middlewareManifest.middleware[middleware] + const functionName = sanitizeName(edgeFunctionDefinition.name) + const matchers = generateEdgeFunctionMiddlewareMatchers({ + edgeFunctionDefinition, + edgeFunctionRoot, + nextConfig, + }) + await writeEdgeFunction({ + edgeFunctionDefinition, + edgeFunctionRoot, + netlifyConfig, + functionName, + matchers, + middleware: true, + }) - for (const middleware of middlewareManifest.sortedMiddleware) { + manifest.functions.push( + ...matchers.map((matcher) => middlewareMatcherToEdgeFunctionDefinition(matcher, functionName)), + ) + } + // Functions (i.e. not middleware, but edge SSR and API routes) + if (typeof middlewareManifest.functions === 'object') { + // When using the app dir, we also need to check if the EF matches a page + const appPathRoutesManifest = await loadAppPathRoutesManifest(netlifyConfig) + + // A map of all route pages to their page regex. This is used for pages dir and appDir. + const pageRegexMap = new Map( + [...(routesManifest.dynamicRoutes || []), ...(routesManifest.staticRoutes || [])].map((route) => [ + route.page, + route.regex, + ]), + ) + // Create a map of pages-dir routes to their data route regex (appDir uses the same route as the HTML) + const dataRoutesMap = new Map( + [...(routesManifest.dataRoutes || [])].map((route) => [route.page, route.dataRouteRegex]), + ) + + for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) { usesEdge = true - const edgeFunctionDefinition = middlewareManifest.middleware[middleware] const functionName = sanitizeName(edgeFunctionDefinition.name) - const matchers = generateEdgeFunctionMiddlewareMatchers({ - edgeFunctionDefinition, - edgeFunctionRoot, - nextConfig, - }) await writeEdgeFunction({ edgeFunctionDefinition, edgeFunctionRoot, netlifyConfig, functionName, - matchers, - middleware: true, }) - - manifest.functions.push( - ...matchers.map((matcher) => middlewareMatcherToEdgeFunctionDefinition(matcher, functionName)), - ) - } - // Functions (i.e. not middleware, but edge SSR and API routes) - if (typeof middlewareManifest.functions === 'object') { - // When using the app dir, we also need to check if the EF matches a page - const appPathRoutesManifest = await loadAppPathRoutesManifest(netlifyConfig) - - // A map of all route pages to their page regex. This is used for pages dir and appDir. - const pageRegexMap = new Map( - [...(routesManifest.dynamicRoutes || []), ...(routesManifest.staticRoutes || [])].map((route) => [ - route.page, - route.regex, - ]), - ) - // Create a map of pages-dir routes to their data route regex (appDir uses the same route as the HTML) - const dataRoutesMap = new Map( - [...(routesManifest.dataRoutes || [])].map((route) => [route.page, route.dataRouteRegex]), - ) - - for (const edgeFunctionDefinition of Object.values(middlewareManifest.functions)) { - usesEdge = true - const functionName = sanitizeName(edgeFunctionDefinition.name) - await writeEdgeFunction({ - edgeFunctionDefinition, - edgeFunctionRoot, - netlifyConfig, - functionName, - }) - const pattern = getEdgeFunctionPatternForPage({ - edgeFunctionDefinition, - pageRegexMap, - appPathRoutesManifest, - }) + const pattern = getEdgeFunctionPatternForPage({ + edgeFunctionDefinition, + pageRegexMap, + appPathRoutesManifest, + }) + manifest.functions.push({ + function: functionName, + name: edgeFunctionDefinition.name, + pattern, + // cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir + cache: usesAppDir ? 'manual' : undefined, + }) + // pages-dir page routes also have a data route. If there's a match, add an entry mapping that to the function too + const dataRoute = dataRoutesMap.get(edgeFunctionDefinition.page) + if (dataRoute) { manifest.functions.push({ function: functionName, name: edgeFunctionDefinition.name, - pattern, - // cache: "manual" is currently experimental, so we restrict it to sites that use experimental appDir + pattern: dataRoute, cache: usesAppDir ? 'manual' : undefined, }) - // pages-dir page routes also have a data route. If there's a match, add an entry mapping that to the function too - const dataRoute = dataRoutesMap.get(edgeFunctionDefinition.page) - if (dataRoute) { - manifest.functions.push({ - function: functionName, - name: edgeFunctionDefinition.name, - pattern: dataRoute, - cache: usesAppDir ? 'manual' : undefined, - }) - } } } - if (usesEdge) { - console.log(outdent` - ✨ Deploying middleware and functions to ${greenBright`Netlify Edge Functions`} ✨ - This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge - `) + } + + + if (destr(process.env.NEXT_FORCE_EDGE_IMAGES)) { + if ( + !destr(process.env.NEXT_DISABLE_EDGE_IMAGES) && + !destr(process.env.DISABLE_IPX) + ) { + usesEdge = true + console.log( + 'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.', + ) + const edgeFunctionDir = join(edgeFunctionRoot, 'ipx') + await ensureDir(edgeFunctionDir) + await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' }) + await copyFile( + join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'), + join(edgeFunctionDir, 'imageconfig.json'), + ) + manifest.functions.push({ + function: 'ipx', + name: 'next/image handler', + path: '/_next/image*', + }) } } + + if (usesEdge) { + console.log(outdent` + ✨ Deploying middleware and functions to ${greenBright`Netlify Edge Functions`} ✨ + This feature is in beta. Please share your feedback here: https://ntl.fyi/next-netlify-edge + `) + } + + await writeJson(join(edgeFunctionRoot, 'manifest.json'), manifest) } diff --git a/test/index.spec.js b/test/index.spec.js index 1979e81407..91192e7e5f 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -684,12 +684,27 @@ describe('onBuild()', () => { }) }) - test('generates an ipx function by default', async () => { + // Skipped while edge images are off by default + test.skip('generates an edge ipx function by default', async () => { await moveNextDist() await nextRuntime.onBuild(defaultArgs) expect(existsSync(path.join('.netlify', 'functions-internal', '_ipx', '_ipx.js'))).toBeTruthy() }) + // Enabled while edge images are off by default + test('does not generate an ipx edge function by default', async () => { + await moveNextDist() + await nextRuntime.onBuild(defaultArgs) + expect(existsSync(path.join('.netlify', 'edge-functions', 'ipx', 'index.ts'))).toBeFalsy() + }) + + test('generates an ipx edge function if force is set', async () => { + process.env.NEXT_FORCE_EDGE_IMAGES = '1' + await moveNextDist() + await nextRuntime.onBuild(defaultArgs) + expect(existsSync(path.join('.netlify', 'edge-functions', 'ipx', 'index.ts'))).toBeTruthy() + }) + test('does not generate an ipx function when DISABLE_IPX is set', async () => { process.env.DISABLE_IPX = '1' await moveNextDist() From a2dd1f1e786f07ac6506120cae5a251cd76c15a3 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Wed, 22 Feb 2023 16:46:40 -0500 Subject: [PATCH 02/13] chore: lint --- packages/runtime/src/helpers/edge.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 3692eb7b37..e209ce40d4 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -452,8 +452,7 @@ export const writeEdgeFunctions = async ({ } - if (destr(process.env.NEXT_FORCE_EDGE_IMAGES)) { - if ( + if (destr(process.env.NEXT_FORCE_EDGE_IMAGES) && !destr(process.env.NEXT_DISABLE_EDGE_IMAGES) && !destr(process.env.DISABLE_IPX) ) { @@ -474,7 +473,6 @@ export const writeEdgeFunctions = async ({ path: '/_next/image*', }) } - } if (usesEdge) { console.log(outdent` From e66ae0bbfc8432e7eb381f8d29251a35be3cbc02 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Wed, 22 Feb 2023 16:47:19 -0500 Subject: [PATCH 03/13] chore: prettier --- packages/runtime/src/helpers/edge.ts | 45 ++++++++++++++-------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index e209ce40d4..7864819209 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -451,28 +451,28 @@ export const writeEdgeFunctions = async ({ } } - - if (destr(process.env.NEXT_FORCE_EDGE_IMAGES) && - !destr(process.env.NEXT_DISABLE_EDGE_IMAGES) && - !destr(process.env.DISABLE_IPX) - ) { - usesEdge = true - console.log( - 'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.', - ) - const edgeFunctionDir = join(edgeFunctionRoot, 'ipx') - await ensureDir(edgeFunctionDir) - await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' }) - await copyFile( - join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'), - join(edgeFunctionDir, 'imageconfig.json'), - ) - manifest.functions.push({ - function: 'ipx', - name: 'next/image handler', - path: '/_next/image*', - }) - } + if ( + destr(process.env.NEXT_FORCE_EDGE_IMAGES) && + !destr(process.env.NEXT_DISABLE_EDGE_IMAGES) && + !destr(process.env.DISABLE_IPX) + ) { + usesEdge = true + console.log( + 'Using Netlify Edge Functions for image format detection. Set env var "NEXT_DISABLE_EDGE_IMAGES=true" to disable.', + ) + const edgeFunctionDir = join(edgeFunctionRoot, 'ipx') + await ensureDir(edgeFunctionDir) + await copyEdgeSourceFile({ edgeFunctionDir, file: 'ipx.ts', target: 'index.ts' }) + await copyFile( + join('.netlify', 'functions-internal', '_ipx', 'imageconfig.json'), + join(edgeFunctionDir, 'imageconfig.json'), + ) + manifest.functions.push({ + function: 'ipx', + name: 'next/image handler', + path: '/_next/image*', + }) + } if (usesEdge) { console.log(outdent` @@ -481,6 +481,5 @@ export const writeEdgeFunctions = async ({ `) } - await writeJson(join(edgeFunctionRoot, 'manifest.json'), manifest) } From 0869b73979076c7ef5ae716521a487f8c55e9d5a Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Wed, 22 Feb 2023 17:04:08 -0500 Subject: [PATCH 04/13] feat: add to Readme --- README.md | 52 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 52284fb088..6fbeac795c 100644 --- a/README.md +++ b/README.md @@ -15,17 +15,23 @@ commands separately will not work, because the Next.js Runtime will not generate If you use [`next/image`](https://nextjs.org/docs/basic-features/image-optimization), your images will be automatically optimized at runtime, ensuring that they are served at the best size and format. The image will be processed on the -first request which means it may take longer to load, but the generated image is then cached at the edge and served as a -static file to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a new -image format with wide browser support that will usually generate smaller files than png or jpg. You can additionally -enable the AVIF format, which is often even smaller in filesize than WebP. The drawback is that with particularly large -images AVIF may take too long to generate, meaning the function times-out. You can configure +first request which means it may take longer to load, but the generated image is then cached and served as a static file +to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a new image format +with wide browser support that will usually generate smaller files than png or jpg. You can additionally enable the AVIF +format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images AVIF may +take too long to generate, meaning the function times-out. You can configure [the supported image formats](https://nextjs.org/docs/api-reference/next/image#acceptable-formats) in your `next.config.js` file. +### Enabling Edge Images + +It is possible to run image content negotiation on the edge. This allows images to be processed on the first request, +and then in future loads, it will be served from cache on the edge. + In order to deliver the correct format to a visitor's browser, this uses a Netlify Edge Function. In some cases your -site may not support Edge Functions, in which case it will instead fall back to delivering the original file format. You -may also manually disable the Edge Function by setting the environment variable `NEXT_DISABLE_EDGE_IMAGES` to `true`. +site may not support Edge Functions, in which case it will instead fall back to delivering the original file format. + +To turn on Edge image handling for Next/Image, set the environment variable `NEXT_FORCE_EDGE_IMAGES` to `true` ## Returning custom response headers on images handled by `ipx` @@ -44,11 +50,14 @@ by targeting the `/_next/image/*` route: ## Disabling included image loader -If you wish to disable the use of the image loader which is bundled into the runtime by default, set the `DISABLE_IPX` environment variable to `true`. +If you wish to disable the use of the image loader which is bundled into the runtime by default, set the `DISABLE_IPX` +environment variable to `true`. -This should only be done if the site is not using `next/image` or is using a different loader (such as Cloudinary or Imgix). +This should only be done if the site is not using `next/image` or is using a different loader (such as Cloudinary or +Imgix). -See the [Next.js documentation](https://nextjs.org/docs/api-reference/next/image#built-in-loaders) for image loader options. +See the [Next.js documentation](https://nextjs.org/docs/api-reference/next/image#built-in-loaders) for image loader +options. ## Next.js Middleware on Netlify @@ -56,11 +65,13 @@ Next.js Middleware works out of the box on Netlify. By default, middleware runs support for running Middleware at the origin, set the environment variable `NEXT_DISABLE_NETLIFY_EDGE` to `true`. Be aware that this will result in slower performance, as all pages that match middleware must use SSR. -For more details on Next.js Middleware with Netlify, see the [middleware docs](https://docs.netlify.com/integrations/frameworks/next-js/middleware/). +For more details on Next.js Middleware with Netlify, see the +[middleware docs](https://docs.netlify.com/integrations/frameworks/next-js/middleware/). ### Limitations -Due to how the site configuration is handled when it's run using Netlify Edge Functions, data such as `locale` and `defaultLocale` will be missing on the `req.nextUrl` object when running `netlify dev`. +Due to how the site configuration is handled when it's run using Netlify Edge Functions, data such as `locale` and +`defaultLocale` will be missing on the `req.nextUrl` object when running `netlify dev`. However, this data is available on `req.nextUrl` in a production environment. @@ -112,8 +123,9 @@ following ways: ### From the UI (Recommended): -You can go to the [UI](https://app.netlify.com/plugins/@netlify/plugin-nextjs/install) and choose the site to install the Next.js Runtime on. This method -is recommended because you will benefit from auto-upgrades to important fixes and feature updates. +You can go to the [UI](https://app.netlify.com/plugins/@netlify/plugin-nextjs/install) and choose the site to install +the Next.js Runtime on. This method is recommended because you will benefit from auto-upgrades to important fixes and +feature updates. ### From `npm`: @@ -139,9 +151,9 @@ If you previously set these values, they're no longer needed and should be remov - `external_node_modules` in `netlify.toml` - The environment variable `NEXT_USE_NETLIFY_EDGE` can be removed as this is now the default -The `serverless` and `experimental-serverless-trace` targets are deprecated in Next.js 12, and all builds with this Next.js -Runtime will now use the default `server` target. If you previously set the target in your `next.config.js`, you should -remove it. +The `serverless` and `experimental-serverless-trace` targets are deprecated in Next.js 12, and all builds with this +Next.js Runtime will now use the default `server` target. If you previously set the target in your `next.config.js`, you +should remove it. If you currently use redirects or rewrites on your site, see [the Rewrites and Redirects guide](https://docs.netlify.com/integrations/frameworks/next-js/redirects-and-rewrites/) for @@ -149,8 +161,10 @@ information on changes to how they are handled in this version. In particular, n files must be placed in `public`, not in the root of the site. ## Using with pnpm -If your site uses pnpm to manage dependencies, currently you must [enable public hoisting](https://pnpm.io/npmrc#public-hoist-pattern). -The simplest way to do this is to create a `.npmrc` file in the root of your project with the content: + +If your site uses pnpm to manage dependencies, currently you must +[enable public hoisting](https://pnpm.io/npmrc#public-hoist-pattern). The simplest way to do this is to create a +`.npmrc` file in the root of your project with the content: ```ini public-hoist-pattern[]=* From 0bde7bc0f4873dd1f5da7ff3abdcaae17412de13 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Thu, 23 Feb 2023 11:33:36 -0500 Subject: [PATCH 05/13] chore: add log line on how to enable edge images --- packages/runtime/src/helpers/edge.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 7864819209..b33e4158e0 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -472,6 +472,10 @@ export const writeEdgeFunctions = async ({ name: 'next/image handler', path: '/_next/image*', }) + } else { + console.log( + 'You are not using Netlify Edge Functions for image format detection. Set env var "NEXT_FORCE_EDGE_IMAGES=true" to enable.', + ) } if (usesEdge) { From 8478cd115bc9c7df6a52dd90100e1cf9d616858d Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Thu, 23 Feb 2023 12:05:39 -0500 Subject: [PATCH 06/13] chore: adding log message for early exit --- packages/runtime/src/helpers/edge.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index b33e4158e0..4966d87e35 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -360,6 +360,9 @@ export const writeEdgeFunctions = async ({ // early return if edge is disabled if (destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) { + console.log( + 'Environment variable NEXT_DISABLE_NETLIFY_EDGE has been set, skipping Netlify Edge Function creation.', + ) return } From c2a7210083c8f9474a14b4b2ead71afaa4db54eb Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Thu, 23 Feb 2023 12:06:17 -0500 Subject: [PATCH 07/13] chore: format --- packages/runtime/src/helpers/edge.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 4966d87e35..b77526642e 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -360,9 +360,7 @@ export const writeEdgeFunctions = async ({ // early return if edge is disabled if (destr(process.env.NEXT_DISABLE_NETLIFY_EDGE)) { - console.log( - 'Environment variable NEXT_DISABLE_NETLIFY_EDGE has been set, skipping Netlify Edge Function creation.', - ) + console.log('Environment variable NEXT_DISABLE_NETLIFY_EDGE has been set, skipping Netlify Edge Function creation.') return } From 475185d7f6352fd6553faa69f4ba340fd0462677 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Thu, 23 Feb 2023 13:41:55 -0500 Subject: [PATCH 08/13] fix: unskip test --- test/index.spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/index.spec.js b/test/index.spec.js index 91192e7e5f..ba6438dbd6 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -684,8 +684,7 @@ describe('onBuild()', () => { }) }) - // Skipped while edge images are off by default - test.skip('generates an edge ipx function by default', async () => { + test('generates an ipx function by default', async () => { await moveNextDist() await nextRuntime.onBuild(defaultArgs) expect(existsSync(path.join('.netlify', 'functions-internal', '_ipx', '_ipx.js'))).toBeTruthy() From cb5458670499649dfb10d80422e9f4d1b5f7ec8b Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Tue, 28 Feb 2023 15:09:56 -0500 Subject: [PATCH 09/13] Update README.md Co-authored-by: Stephanie <52582720+stephmarie17@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6fbeac795c..d84551d39b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ If you use [`next/image`](https://nextjs.org/docs/basic-features/image-optimizat optimized at runtime, ensuring that they are served at the best size and format. The image will be processed on the first request which means it may take longer to load, but the generated image is then cached and served as a static file to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a new image format -with wide browser support that will usually generate smaller files than png or jpg. You can additionally enable the AVIF +with wide browser support that will usually generate smaller files than PNG or JPG. Additionally, you can enable AVIF format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images AVIF may take too long to generate, meaning the function times-out. You can configure [the supported image formats](https://nextjs.org/docs/api-reference/next/image#acceptable-formats) in your From 00a675f215ac687ddeb5758cdaa9d2de25dc55d9 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Tue, 28 Feb 2023 15:10:06 -0500 Subject: [PATCH 10/13] Update README.md Co-authored-by: Stephanie <52582720+stephmarie17@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d84551d39b..c96fdc7ddc 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ commands separately will not work, because the Next.js Runtime will not generate If you use [`next/image`](https://nextjs.org/docs/basic-features/image-optimization), your images will be automatically optimized at runtime, ensuring that they are served at the best size and format. The image will be processed on the first request which means it may take longer to load, but the generated image is then cached and served as a static file -to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a new image format +to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a modern image format with wide browser support that will usually generate smaller files than PNG or JPG. Additionally, you can enable AVIF format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images AVIF may take too long to generate, meaning the function times-out. You can configure From 3c0c36246550efbaa7551ac5384fa881a727e006 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Tue, 28 Feb 2023 15:10:25 -0500 Subject: [PATCH 11/13] Update README.md Co-authored-by: Stephanie <52582720+stephmarie17@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c96fdc7ddc..50223c8461 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ optimized at runtime, ensuring that they are served at the best size and format. first request which means it may take longer to load, but the generated image is then cached and served as a static file to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a modern image format with wide browser support that will usually generate smaller files than PNG or JPG. Additionally, you can enable AVIF -format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images AVIF may +format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images, AVIF images may take too long to generate, meaning the function times-out. You can configure [the supported image formats](https://nextjs.org/docs/api-reference/next/image#acceptable-formats) in your `next.config.js` file. From c74a6c4cc3998af31a1e130a8de181d26c4d13d0 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Tue, 28 Feb 2023 15:10:51 -0500 Subject: [PATCH 12/13] chore: Update README.md Co-authored-by: Stephanie <52582720+stephmarie17@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 50223c8461..dae730a219 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ first request which means it may take longer to load, but the generated image is to future visitors. By default, Next.js will deliver WebP images if the browser supports it. WebP is a modern image format with wide browser support that will usually generate smaller files than PNG or JPG. Additionally, you can enable AVIF format, which is often even smaller in filesize than WebP. The drawback is that with particularly large images, AVIF images may -take too long to generate, meaning the function times-out. You can configure +take too long to generate, and the function times-out. You can configure [the supported image formats](https://nextjs.org/docs/api-reference/next/image#acceptable-formats) in your `next.config.js` file. From 3dd6a237229302992e066dbb79b2dc9f72ec3d68 Mon Sep 17 00:00:00 2001 From: Sarah Etter Date: Tue, 28 Feb 2023 15:11:03 -0500 Subject: [PATCH 13/13] chore: Update README.md Co-authored-by: Stephanie <52582720+stephmarie17@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dae730a219..5c6d561c27 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ take too long to generate, and the function times-out. You can configure ### Enabling Edge Images It is possible to run image content negotiation on the edge. This allows images to be processed on the first request, -and then in future loads, it will be served from cache on the edge. +and then, in future loads, served from cache on the edge. In order to deliver the correct format to a visitor's browser, this uses a Netlify Edge Function. In some cases your site may not support Edge Functions, in which case it will instead fall back to delivering the original file format.