Skip to content

Commit 04c87ae

Browse files
ojj1123styfle
andauthored
fix: show the error message if images.loaderFile doesn't export a default 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>
1 parent 0c88131 commit 04c87ae

File tree

8 files changed

+104
-0
lines changed

8 files changed

+104
-0
lines changed

packages/next/src/shared/lib/get-img-props.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ export function getImgProps(
285285
config = { ...c, allSizes, deviceSizes }
286286
}
287287

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

290295
// Remove property so it's not spread on <img> element
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { getImageProps } from 'next/image'
2+
3+
export default function Page() {
4+
const { props: imageProps } = getImageProps({
5+
id: 'logo',
6+
alt: 'logo',
7+
src: '/logo.png',
8+
width: '400',
9+
height: '400',
10+
})
11+
12+
return (
13+
<div>
14+
<img {...imageProps} />
15+
</div>
16+
)
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default function Root({ children }: { children: React.ReactNode }) {
2+
return (
3+
<html>
4+
<body>{children}</body>
5+
</html>
6+
)
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Image from 'next/image'
2+
3+
export default function Page() {
4+
return (
5+
<p>
6+
<Image id="logo" alt="logo" src="/logo.png" width="400" height="400" />
7+
</p>
8+
)
9+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export function dummyLoader({ src, width, quality }) {
2+
return `/_next/image/?url=${src}&w=${width}&q=${quality || 50}`
3+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { nextTestSetup } from 'e2e-utils'
2+
import { getRedboxHeader, hasRedbox } from 'next-test-utils'
3+
4+
const errorMessage =
5+
'images.loaderFile detected but the file is missing default export.\nRead more: https://nextjs.org/docs/messages/invalid-images-config'
6+
7+
async function testDev(browser, errorRegex) {
8+
expect(await hasRedbox(browser)).toBe(true)
9+
expect(await getRedboxHeader(browser)).toMatch(errorRegex)
10+
}
11+
12+
describe('Error test if the loader file export a named function', () => {
13+
describe('in Development', () => {
14+
const { next, isNextDev } = nextTestSetup({
15+
skipDeployment: true,
16+
files: __dirname,
17+
})
18+
19+
;(isNextDev ? describe : describe.skip)('development only', () => {
20+
it('should show the error when using `Image` component', async () => {
21+
const browser = await next.browser('/')
22+
await testDev(browser, errorMessage)
23+
})
24+
25+
it('should show the error when using `getImageProps` method', async () => {
26+
const browser = await next.browser('/get-img-props')
27+
await testDev(browser, errorMessage)
28+
})
29+
})
30+
})
31+
32+
describe('in Build and Start', () => {
33+
const { next, isNextStart } = nextTestSetup({
34+
skipDeployment: true,
35+
skipStart: true,
36+
files: __dirname,
37+
})
38+
39+
// next build doesn't support turbopack yet
40+
// see https://nextjs.org/docs/architecture/turbopack#unsupported-features
41+
;(isNextStart && !process.env.TURBOPACK ? describe : describe.skip)(
42+
'build and start only',
43+
() => {
44+
it('should show the build error', async () => {
45+
await expect(next.start()).rejects.toThrow(
46+
'next build failed with code/signal 1'
47+
)
48+
expect(next.cliOutput).toContain(errorMessage)
49+
})
50+
}
51+
)
52+
})
53+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @type {import('next').NextConfig}
3+
*/
4+
const nextConfig = {
5+
images: {
6+
loaderFile: '/dummy-loader.ts',
7+
},
8+
}
9+
10+
module.exports = nextConfig
Loading

0 commit comments

Comments
 (0)