Skip to content
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

Updates next/image eslint message to denote that costs may be incurred. #46640

Merged
merged 8 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 11 additions & 5 deletions errors/no-img-element.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
# No img element

> Prevent usage of `<img>` element to prevent layout shift and favor [optimized images](https://nextjs.org/docs/basic-features/image-optimization).
> Prevent usage of `<img>` element due to slower LCP and higher bandwidth.

### Why This Error Occurred

An `<img>` element was used to display an image.
An `<img>` element was used to display an image instead of `<Image />` from `next/image`.

### Possible Ways to Fix It

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: If deploying to a [managed hosting provider](https://nextjs.org/docs/deployment), remember to check pricing since optimized images might be charged differently than 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.
> Note: If deploying to a [managed hosting provider](https://nextjs.org/docs/deployment), remember to check provider pricing since optimized images might be charged differently than the original images.
>
> Common image optimization platform pricing:
>
> - [Vercel pricing](https://vercel.com/pricing)
> - [Cloudinary pricing](https://cloudinary.com/pricing)
> - [imgix pricing](https://imgix.com]/pricing)
styfle marked this conversation as resolved.
Show resolved Hide resolved

> Note: 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'
Expand All @@ -31,8 +39,6 @@ export default Home

If you would like to use `next/image` features such as blur-up placeholders but disable Image Optimization, you can do so using [unoptimized](https://nextjs.org/docs/api-reference/next/image#unoptimized).

<br />

Or, use a `<picture>` element with the nested `<img>` element:

```jsx
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin-next/src/rules/no-img-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export = defineRule({

context.report({
node,
message: `Using \`<img>\` could result in slower LCP and higher bandwidth. Use \`<Image />\` from \`next/image\` instead to utilize Image Optimization. See: ${url}`,
message: `Using \`<img>\` could result in slower LCP and higher bandwidth. Consider using \`<Image />\` from \`next/image\` to automatically optimize images. This may incur additional usage or cost from your provider. See: ${url}`,
})
},
}
Expand Down
20 changes: 10 additions & 10 deletions test/integration/eslint/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ describe('ESLint', () => {
'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
)
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Warning: Do not include stylesheets manually')
expect(output).toContain(
Expand Down Expand Up @@ -143,7 +143,7 @@ describe('ESLint', () => {
'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
)
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Warning: Do not include stylesheets manually')
expect(output).toContain(
Expand Down Expand Up @@ -417,7 +417,7 @@ describe('ESLint', () => {
'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
)
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Warning: Do not include stylesheets manually')
expect(output).toContain(
Expand Down Expand Up @@ -453,7 +453,7 @@ describe('ESLint', () => {
'Error: `next/head` should not be imported in `pages/_document.js`. Use `<Head />` from `next/document` instead'
)
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Warning: Do not include stylesheets manually')
expect(output).toContain(
Expand All @@ -479,7 +479,7 @@ describe('ESLint', () => {

const output = stdout + stderr
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Error: Synchronous scripts should not be used.')
})
Expand Down Expand Up @@ -515,7 +515,7 @@ describe('ESLint', () => {

const output = stdout + stderr
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)
expect(output).toContain('Error: Synchronous scripts should not be used.')
})
Expand Down Expand Up @@ -788,7 +788,7 @@ describe('ESLint', () => {

expect(output).toContain('pages/bar.js')
expect(output).toContain(
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization.'
'Warning: Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images.'
)

expect(output).not.toContain('pages/index.js')
Expand Down Expand Up @@ -833,7 +833,7 @@ describe('ESLint', () => {
}),
expect.objectContaining({
message:
'Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element',
'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element',
}),
])
)
Expand Down Expand Up @@ -872,7 +872,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 `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element'
'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element'
)

expect(fileOutput).toContain('file-linting/pages/index.js')
Expand Down Expand Up @@ -912,7 +912,7 @@ describe('ESLint', () => {
'img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.'
)
expect(output).toContain(
'Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization. See: https://nextjs.org/docs/messages/no-img-element'
'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element'
)

expect(output).toContain('pages/index.cjs')
Expand Down
8 changes: 3 additions & 5 deletions test/unit/eslint-plugin-next/no-img-element.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ ruleTester.run('no-img-element', rule, {
errors: [
{
message:
'Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization. ' +
'See: https://nextjs.org/docs/messages/no-img-element',
'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element',
type: 'JSXOpeningElement',
},
],
Expand All @@ -92,7 +91,7 @@ ruleTester.run('no-img-element', rule, {
export class MyComponent {
render() {
return (
<img
<img
src="/test.png"
alt="Test picture"
width={500}
Expand All @@ -104,8 +103,7 @@ ruleTester.run('no-img-element', rule, {
errors: [
{
message:
'Using `<img>` could result in slower LCP and higher bandwidth. Use `<Image />` from `next/image` instead to utilize Image Optimization. ' +
'See: https://nextjs.org/docs/messages/no-img-element',
'Using `<img>` could result in slower LCP and higher bandwidth. Consider using `<Image />` from `next/image` to automatically optimize images. This may incur additional usage or cost from your provider. See: https://nextjs.org/docs/messages/no-img-element',
type: 'JSXOpeningElement',
},
],
Expand Down