Skip to content

Commit

Permalink
fix: show the error message if images.loaderFile doesn't export a d…
Browse files Browse the repository at this point in the history
…efault function (#64036)

<!-- Thanks for opening a PR! Your contribution is much appreciated.
To make sure your PR is handled as smoothly as possible we request that
you follow the checklist sections below.
Choose the right checklist for the change(s) that you're making:

## For Contributors

### Fixing a bug

- Related issues linked using `fixes #number`
- Tests added. See:
https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs
- Errors have a helpful link attached, see
https://github.com/vercel/next.js/blob/canary/contributing.md

-->

fixes #63803 

## What I do?

- If the loader file export the function as `named`, Next.js throws the
error.
- But this error is a bit confusing for the developers.
- So I open this PR for showing the accurate error message.

## AS-IS / TO-BE

### AS-IS

```
TypeError: Cannot use 'in' operator to search for '__next_img_default' in undefined
```
<img width="1202" alt="스크린샷 2024-03-28 16 10 53"
src="https://github.com/vercel/next.js/assets/33178048/e7c81cb5-7976-46ff-b86f-9c8fd9a7a681">

### TO-BE

```
Error: The loader file must export a default function that returns a string.
See more info here: https://nextjs.org/docs/messages/invalid-images-config
```
<img width="500" alt="스크린샷 2024-03-28 16 10 53"
src="https://github.com/vercel/next.js/assets/33178048/c391e61b-6a44-4f85-8600-28ab6cb5b0eb">

---------

Co-authored-by: Steven <steven@ceriously.com>
  • Loading branch information
ojj1123 and styfle committed Apr 10, 2024
1 parent 0c88131 commit 04c87ae
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/next/src/shared/lib/get-img-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,11 @@ export function getImgProps(
config = { ...c, allSizes, deviceSizes }
}

if (typeof defaultLoader === 'undefined') {
throw new Error(
'images.loaderFile detected but the file is missing default export.\nRead more: https://nextjs.org/docs/messages/invalid-images-config'
)
}
let loader: ImageLoaderWithConfig = rest.loader || defaultLoader

// Remove property so it's not spread on <img> element
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { getImageProps } from 'next/image'

export default function Page() {
const { props: imageProps } = getImageProps({
id: 'logo',
alt: 'logo',
src: '/logo.png',
width: '400',
height: '400',
})

return (
<div>
<img {...imageProps} />
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Image from 'next/image'

export default function Page() {
return (
<p>
<Image id="logo" alt="logo" src="/logo.png" width="400" height="400" />
</p>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function dummyLoader({ src, width, quality }) {
return `/_next/image/?url=${src}&w=${width}&q=${quality || 50}`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { nextTestSetup } from 'e2e-utils'
import { getRedboxHeader, hasRedbox } from 'next-test-utils'

const errorMessage =
'images.loaderFile detected but the file is missing default export.\nRead more: https://nextjs.org/docs/messages/invalid-images-config'

async function testDev(browser, errorRegex) {
expect(await hasRedbox(browser)).toBe(true)
expect(await getRedboxHeader(browser)).toMatch(errorRegex)
}

describe('Error test if the loader file export a named function', () => {
describe('in Development', () => {
const { next, isNextDev } = nextTestSetup({
skipDeployment: true,
files: __dirname,
})

;(isNextDev ? describe : describe.skip)('development only', () => {
it('should show the error when using `Image` component', async () => {
const browser = await next.browser('/')
await testDev(browser, errorMessage)
})

it('should show the error when using `getImageProps` method', async () => {
const browser = await next.browser('/get-img-props')
await testDev(browser, errorMessage)
})
})
})

describe('in Build and Start', () => {
const { next, isNextStart } = nextTestSetup({
skipDeployment: true,
skipStart: true,
files: __dirname,
})

// next build doesn't support turbopack yet
// see https://nextjs.org/docs/architecture/turbopack#unsupported-features
;(isNextStart && !process.env.TURBOPACK ? describe : describe.skip)(
'build and start only',
() => {
it('should show the build error', async () => {
await expect(next.start()).rejects.toThrow(
'next build failed with code/signal 1'
)
expect(next.cliOutput).toContain(errorMessage)
})
}
)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
images: {
loaderFile: '/dummy-loader.ts',
},
}

module.exports = nextConfig
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 04c87ae

Please sign in to comment.