Skip to content

Commit

Permalink
Updates next/image eslint message to denote that costs may be incur…
Browse files Browse the repository at this point in the history
…red. (#46640)

Changes ESLint warning message to still encourage usage of `next/image`
for the best experience, but also denoting that optimization could come
with incurred costs.

## Feature

- [x] Documentation added
- [x] Errors have a helpful link attached, see
[`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md)

## Documentation / Examples

- [x] Make sure the linting passes by running `pnpm build && pnpm lint`
- [x] The "examples guidelines" are followed from [our contributing
doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)

---------

Co-authored-by: Steven Tey <stevensteel97@gmail.com>
Co-authored-by: Steven <steven@ceriously.com>
  • Loading branch information
3 people committed Mar 1, 2023
1 parent 9720ba5 commit 5e112c0
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 21 deletions.
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)
> 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 @@ -435,7 +435,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 @@ -471,7 +471,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 @@ -497,7 +497,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 @@ -533,7 +533,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 @@ -806,7 +806,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 @@ -851,7 +851,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 @@ -890,7 +890,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 @@ -930,7 +930,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

0 comments on commit 5e112c0

Please sign in to comment.