From 77aa35d5280a3ba74c5fddfed6791c53c67ea85a Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Dec 2022 14:35:49 -0500 Subject: [PATCH 1/5] Update `no-img-element` lint rule --- docs/basic-features/eslint.md | 2 +- errors/no-img-element.md | 41 +++++++++++-------- .../src/rules/no-img-element.ts | 5 ++- test/integration/eslint/test/index.test.js | 16 ++++---- .../eslint-plugin-next/no-img-element.test.ts | 4 +- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index b2e3d8652f55..0e86fd40d09d 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -94,7 +94,7 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ | ✔️ | [@next/next/no-head-element](/docs/messages/no-head-element.md) | Prevent usage of `` element. | | ✔️ | [@next/next/no-head-import-in-document](/docs/messages/no-head-import-in-document.md) | Prevent usage of `next/head` in `pages/_document.js`. | | ✔️ | [@next/next/no-html-link-for-pages](/docs/messages/no-html-link-for-pages.md) | Prevent usage of `` elements to navigate to internal Next.js pages. | -| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `` element to prevent layout shift. | +| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `` element to prevent layout shift and favor optimized images. | | ✔️ | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font.md) | Prevent page-only custom fonts. | | ✔️ | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head.md) | Prevent usage of `next/script` in `next/head` component. | | ✔️ | [@next/next/no-styled-jsx-in-document](/docs/messages/no-styled-jsx-in-document.md) | Prevent usage of `styled-jsx` in `pages/_document.js`. | diff --git a/errors/no-img-element.md b/errors/no-img-element.md index 1e4d9f651442..21052ec5ed88 100644 --- a/errors/no-img-element.md +++ b/errors/no-img-element.md @@ -1,28 +1,28 @@ # No Img Element -> Prevent usage of `` element to prevent layout shift. +> Prevent usage of `` element to prevent layout shift and favor [optimized images](https://nextjs.org/docs/basic-features/image-optimization). ### Why This Error Occurred -An `` element was used to display an image. Use either `` in conjunction with `` element, or use `next/image` that has better performance and automatic Image Optimization over ``. +An `` element was used to display an image. ### Possible Ways to Fix It -Import and use the `` component: +Use [`next/image`](https://nextjs.org/docs/api-reference/next/image) to improve performance with automatic [Image Optimization](https://nextjs.org/docs/basic-features/image-optimization). + +> Note: Remember to check the pricing of your [deployment provider](https://nextjs.org/docs/deployment) before enabling Image Optimization because billing for optimized images might be charged differently that the original images. When self-hosting, Image Optimization will use more disk space to cache optimized images. ```jsx import Image from 'next/image' function Home() { return ( - <> - Landscape picture - + Landscape picture ) } @@ -31,17 +31,21 @@ export default Home
-Use `` in conjunction with `` element: +Or, use a `` element with the nested `` element: ```jsx function Home() { return ( - <> - - - Landscape picture - - + + + + Landscape picture + ) } ``` @@ -49,3 +53,4 @@ function Home() { ### Useful Links - [Image Component and Image Optimization](https://nextjs.org/docs/basic-features/image-optimization) +- [next/image API Reference](https://nextjs.org/docs/api-reference/next/image) diff --git a/packages/eslint-plugin-next/src/rules/no-img-element.ts b/packages/eslint-plugin-next/src/rules/no-img-element.ts index 0a5e5e4dcd32..2df6e771ea8a 100644 --- a/packages/eslint-plugin-next/src/rules/no-img-element.ts +++ b/packages/eslint-plugin-next/src/rules/no-img-element.ts @@ -5,7 +5,8 @@ const url = 'https://nextjs.org/docs/messages/no-img-element' export = defineRule({ meta: { docs: { - description: 'Prevent usage of `` element to prevent layout shift.', + description: + 'Prevent usage of `` element to prevent layout shift favor optimized images.', category: 'HTML', recommended: true, url, @@ -30,7 +31,7 @@ export = defineRule({ context.report({ node, - message: `Do not use \`\` element. Use \`\` from \`next/image\` instead. See: ${url}`, + message: `The \`\` element does not benefit from Image Optimization. Use \`\` from \`next/image\` instead. See: ${url}`, }) }, } diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index 5c03a46ec14b..cf8a6e17bde8 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -94,7 +94,7 @@ describe('ESLint', () => { 'Error: `next/head` should not be imported in `pages/_document.js`. Use `` from `next/document` instead' ) expect(output).toContain( - 'Warning: Do not use `` element. Use `` from `next/image` instead' + 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead' ) expect(output).toContain('Warning: Do not include stylesheets manually') expect(output).toContain( @@ -327,7 +327,7 @@ describe('ESLint', () => { 'Error: `next/head` should not be imported in `pages/_document.js`. Use `` from `next/document` instead' ) expect(output).toContain( - 'Warning: Do not use `` element. Use `` from `next/image` instead' + 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead' ) expect(output).toContain('Warning: Do not include stylesheets manually') expect(output).toContain( @@ -349,7 +349,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: Do not use `` element. Use `` from `next/image` instead.' + 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' ) expect(output).toContain('Error: Synchronous scripts should not be used.') }) @@ -385,7 +385,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: Do not use `` element. Use `` from `next/image` instead.' + 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' ) expect(output).toContain('Error: Synchronous scripts should not be used.') }) @@ -658,7 +658,7 @@ describe('ESLint', () => { expect(output).toContain('pages/bar.js') expect(output).toContain( - 'Do not use `` element. Use `` from `next/image` instead.' + 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' ) expect(output).not.toContain('pages/index.js') @@ -703,7 +703,7 @@ describe('ESLint', () => { }), expect.objectContaining({ message: - 'Do not use `` element. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element', + 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element', }), ]) ) @@ -742,7 +742,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(fileOutput).toContain( - 'Do not use `` element. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' + 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' ) expect(fileOutput).toContain('file-linting/pages/index.js') @@ -782,7 +782,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(output).toContain( - 'Do not use `` element. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' + 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' ) expect(output).toContain('pages/index.cjs') diff --git a/test/unit/eslint-plugin-next/no-img-element.test.ts b/test/unit/eslint-plugin-next/no-img-element.test.ts index 1349524709df..5a9ea0010de2 100644 --- a/test/unit/eslint-plugin-next/no-img-element.test.ts +++ b/test/unit/eslint-plugin-next/no-img-element.test.ts @@ -81,7 +81,7 @@ ruleTester.run('no-img-element', rule, { errors: [ { message: - 'Do not use `` element. Use `` from `next/image` instead. ' + + 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. ' + 'See: https://nextjs.org/docs/messages/no-img-element', type: 'JSXOpeningElement', }, @@ -104,7 +104,7 @@ ruleTester.run('no-img-element', rule, { errors: [ { message: - 'Do not use `` element. Use `` from `next/image` instead. ' + + 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. ' + 'See: https://nextjs.org/docs/messages/no-img-element', type: 'JSXOpeningElement', }, From bd5c3a46f705f1d632275c5807adef6098028375 Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Dec 2022 15:28:47 -0500 Subject: [PATCH 2/5] Update message --- errors/no-img-element.md | 3 ++- .../src/rules/no-img-element.ts | 2 +- test/integration/eslint/test/index.test.js | 16 ++++++++-------- .../eslint-plugin-next/no-img-element.test.ts | 4 ++-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/errors/no-img-element.md b/errors/no-img-element.md index 21052ec5ed88..2aa32f48ed20 100644 --- a/errors/no-img-element.md +++ b/errors/no-img-element.md @@ -10,7 +10,7 @@ An `` element was used to display an image. Use [`next/image`](https://nextjs.org/docs/api-reference/next/image) to improve performance with automatic [Image Optimization](https://nextjs.org/docs/basic-features/image-optimization). -> Note: Remember to check the pricing of your [deployment provider](https://nextjs.org/docs/deployment) before enabling Image Optimization because billing for optimized images might be charged differently that the original images. When self-hosting, Image Optimization will use more disk space to cache optimized images. +> Note: If deploying to a [managed hosting provider](https://nextjs.org/docs/deployment), remember to check pricing since optimized images might be charged differently that the original images. If self-hosting, remember to install [`sharp`](https://www.npmjs.com/package/sharp) and check if your server has enough storage to cache the optimized images. ```jsx import Image from 'next/image' @@ -54,3 +54,4 @@ function Home() { - [Image Component and Image Optimization](https://nextjs.org/docs/basic-features/image-optimization) - [next/image API Reference](https://nextjs.org/docs/api-reference/next/image) +- [Largest Contentful Paint (LCP)](https://nextjs.org/learn/seo/web-performance/lcp) diff --git a/packages/eslint-plugin-next/src/rules/no-img-element.ts b/packages/eslint-plugin-next/src/rules/no-img-element.ts index 2df6e771ea8a..1e9d342311bb 100644 --- a/packages/eslint-plugin-next/src/rules/no-img-element.ts +++ b/packages/eslint-plugin-next/src/rules/no-img-element.ts @@ -31,7 +31,7 @@ export = defineRule({ context.report({ node, - message: `The \`\` element does not benefit from Image Optimization. Use \`\` from \`next/image\` instead. See: ${url}`, + message: `Using \`\` could result in slower LCP and higher bandwidth. Use \`\` from \`next/image\` instead to utilize Image Optimization. See: ${url}`, }) }, } diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index cf8a6e17bde8..3e5700cbcc77 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -94,7 +94,7 @@ describe('ESLint', () => { 'Error: `next/head` should not be imported in `pages/_document.js`. Use `` from `next/document` instead' ) expect(output).toContain( - 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead' + 'Warning: Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization.' ) expect(output).toContain('Warning: Do not include stylesheets manually') expect(output).toContain( @@ -327,7 +327,7 @@ describe('ESLint', () => { 'Error: `next/head` should not be imported in `pages/_document.js`. Use `` from `next/document` instead' ) expect(output).toContain( - 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead' + 'Warning: Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization.' ) expect(output).toContain('Warning: Do not include stylesheets manually') expect(output).toContain( @@ -349,7 +349,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' + 'Warning: Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization.' ) expect(output).toContain('Error: Synchronous scripts should not be used.') }) @@ -385,7 +385,7 @@ describe('ESLint', () => { const output = stdout + stderr expect(output).toContain( - 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' + 'Warning: Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization.' ) expect(output).toContain('Error: Synchronous scripts should not be used.') }) @@ -658,7 +658,7 @@ describe('ESLint', () => { expect(output).toContain('pages/bar.js') expect(output).toContain( - 'Warning: The `` element does not benefit from Image Optimization. Use `` from `next/image` instead.' + 'Warning: Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization.' ) expect(output).not.toContain('pages/index.js') @@ -703,7 +703,7 @@ describe('ESLint', () => { }), expect.objectContaining({ message: - 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element', + 'Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element', }), ]) ) @@ -742,7 +742,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(fileOutput).toContain( - 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' + "Using `` could result in slower LCP and higher bandwidth because it doesn't utilize Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element" ) expect(fileOutput).toContain('file-linting/pages/index.js') @@ -782,7 +782,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(output).toContain( - 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element' + 'Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element' ) expect(output).toContain('pages/index.cjs') diff --git a/test/unit/eslint-plugin-next/no-img-element.test.ts b/test/unit/eslint-plugin-next/no-img-element.test.ts index 5a9ea0010de2..9f46744d1af4 100644 --- a/test/unit/eslint-plugin-next/no-img-element.test.ts +++ b/test/unit/eslint-plugin-next/no-img-element.test.ts @@ -81,7 +81,7 @@ ruleTester.run('no-img-element', rule, { errors: [ { message: - 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. ' + + 'Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization. ' + 'See: https://nextjs.org/docs/messages/no-img-element', type: 'JSXOpeningElement', }, @@ -104,7 +104,7 @@ ruleTester.run('no-img-element', rule, { errors: [ { message: - 'The `` element does not benefit from Image Optimization. Use `` from `next/image` instead. ' + + 'Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization. ' + 'See: https://nextjs.org/docs/messages/no-img-element', type: 'JSXOpeningElement', }, From 54c684f123e243b8506b30a9be34c88aa2e333dd Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Dec 2022 16:37:13 -0500 Subject: [PATCH 3/5] Another update --- docs/basic-features/eslint.md | 2 +- errors/no-img-element.md | 4 +++- packages/eslint-plugin-next/src/rules/no-img-element.ts | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/basic-features/eslint.md b/docs/basic-features/eslint.md index 0e86fd40d09d..6b8a2866c880 100644 --- a/docs/basic-features/eslint.md +++ b/docs/basic-features/eslint.md @@ -94,7 +94,7 @@ Next.js provides an ESLint plugin, [`eslint-plugin-next`](https://www.npmjs.com/ | ✔️ | [@next/next/no-head-element](/docs/messages/no-head-element.md) | Prevent usage of `` element. | | ✔️ | [@next/next/no-head-import-in-document](/docs/messages/no-head-import-in-document.md) | Prevent usage of `next/head` in `pages/_document.js`. | | ✔️ | [@next/next/no-html-link-for-pages](/docs/messages/no-html-link-for-pages.md) | Prevent usage of `
` elements to navigate to internal Next.js pages. | -| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `` element to prevent layout shift and favor optimized images. | +| ✔️ | [@next/next/no-img-element](/docs/messages/no-img-element.md) | Prevent usage of `` element due to slower LCP and higher bandwidth. | | ✔️ | [@next/next/no-page-custom-font](/docs/messages/no-page-custom-font.md) | Prevent page-only custom fonts. | | ✔️ | [@next/next/no-script-component-in-head](/docs/messages/no-script-component-in-head.md) | Prevent usage of `next/script` in `next/head` component. | | ✔️ | [@next/next/no-styled-jsx-in-document](/docs/messages/no-styled-jsx-in-document.md) | Prevent usage of `styled-jsx` in `pages/_document.js`. | diff --git a/errors/no-img-element.md b/errors/no-img-element.md index 2aa32f48ed20..6e5ee55e2d91 100644 --- a/errors/no-img-element.md +++ b/errors/no-img-element.md @@ -1,4 +1,4 @@ -# No Img Element +# No img element > Prevent usage of `` element to prevent layout shift and favor [optimized images](https://nextjs.org/docs/basic-features/image-optimization). @@ -29,6 +29,8 @@ function Home() { export default Home ``` +If you would like to use `next/image` featrues such as blur-up placeholders but disable Image Optimization, you can do so using [unoptimized](https://nextjs.org/docs/api-reference/next/image#unoptimized). +
Or, use a `` element with the nested `` element: diff --git a/packages/eslint-plugin-next/src/rules/no-img-element.ts b/packages/eslint-plugin-next/src/rules/no-img-element.ts index 1e9d342311bb..4e4aa8cbe7f3 100644 --- a/packages/eslint-plugin-next/src/rules/no-img-element.ts +++ b/packages/eslint-plugin-next/src/rules/no-img-element.ts @@ -6,7 +6,7 @@ export = defineRule({ meta: { docs: { description: - 'Prevent usage of `` element to prevent layout shift favor optimized images.', + 'Prevent usage of `` element due to slower LCP and higher bandwidth.', category: 'HTML', recommended: true, url, From 0e4aef764e63a1cd1f4b116c103df37100ba5554 Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Dec 2022 16:39:12 -0500 Subject: [PATCH 4/5] fix one --- test/integration/eslint/test/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index 3e5700cbcc77..77f4eea0ae3b 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -742,7 +742,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(fileOutput).toContain( - "Using `` could result in slower LCP and higher bandwidth because it doesn't utilize Image Optimization. Use `` from `next/image` instead. See: https://nextjs.org/docs/messages/no-img-element" + "Using `` could result in slower LCP and higher bandwidth because it doesn't utilize Image Optimization. Use `` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element" ) expect(fileOutput).toContain('file-linting/pages/index.js') From 9b17fb2ffe833f605377d5dfe28acadee2a1c140 Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 12 Dec 2022 19:16:40 -0500 Subject: [PATCH 5/5] Fix another test --- test/integration/eslint/test/index.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/eslint/test/index.test.js b/test/integration/eslint/test/index.test.js index 77f4eea0ae3b..1651e8534b33 100644 --- a/test/integration/eslint/test/index.test.js +++ b/test/integration/eslint/test/index.test.js @@ -742,7 +742,7 @@ describe('ESLint', () => { 'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.' ) expect(fileOutput).toContain( - "Using `` could result in slower LCP and higher bandwidth because it doesn't utilize Image Optimization. Use `` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element" + 'Using `` could result in slower LCP and higher bandwidth. Use `` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element' ) expect(fileOutput).toContain('file-linting/pages/index.js')