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

Add pretty error when image import is invalid format #41267

Merged
merged 5 commits into from Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 8 additions & 2 deletions packages/next/build/webpack/loaders/next-image-loader.js
Expand Up @@ -17,16 +17,22 @@ function nextImageLoader(content) {
opts
)
const outputPath = assetPrefix + '/_next' + interpolatedName

let extension = loaderUtils.interpolateName(this, '[ext]', opts)
if (extension === 'jpg') {
extension = 'jpeg'
}

const imageSizeSpan = imageLoaderSpan.traceChild('image-size-calculation')
const imageSize = await imageSizeSpan.traceAsyncFn(() =>
getImageSize(content, extension)
getImageSize(content, extension).catch((err) => err)
)

if (imageSize instanceof Error) {
const err = imageSize
err.name = 'InvalidImageFormatError'
throw err
}

let blurDataURL
let blurWidth
let blurHeight
Expand Down
Expand Up @@ -118,3 +118,35 @@ export async function getNotFoundError(
return input
}
}

export async function getImageError(
compilation: any,
input: any,
err: Error
): Promise<SimpleWebpackError | false> {
if (err.name !== 'InvalidImageFormatError') {
return false
}

const moduleTrace = getModuleTrace(input, compilation)
const { origin, module } = moduleTrace[0] || {}
if (!origin || !module) {
return false
}
const page = origin.rawRequest.replace(/^private-next-pages/, './pages')
const importedFile = module.rawRequest
const source = origin.originalSource().buffer().toString('utf8') as string
let lineNumber = -1
source.split('\n').some((line) => {
lineNumber++
return line.includes(importedFile)
})
return new SimpleWebpackError(
`${chalk.cyan(page)}:${chalk.yellow(lineNumber.toString())}`,
chalk.red
.bold('Error')
.concat(
`: Image import "${importedFile}" is not a valid image file. The image may be corrupted or an unsupported format.`
)
)
}
Expand Up @@ -5,7 +5,7 @@ import type { webpack } from 'next/dist/compiled/webpack/webpack'
import { getBabelError } from './parseBabel'
import { getCssError } from './parseCss'
import { getScssError } from './parseScss'
import { getNotFoundError } from './parseNotFoundError'
import { getNotFoundError, getImageError } from './parseNotFoundError'
import { SimpleWebpackError } from './simpleWebpackError'
import isError from '../../../../lib/is-error'
import { getRscError } from './parseRSC'
Expand Down Expand Up @@ -71,6 +71,11 @@ export async function getModuleBuildError(
return notFoundError
}

const imageError = await getImageError(compilation, input, err)
if (imageError !== false) {
return imageError
}

const babel = getBabelError(sourceFilename, err)
if (babel !== false) {
return babel
Expand Down
@@ -0,0 +1,14 @@
import React from 'react'
import Image from 'next/future/image'
import test from '../public/invalid.svg'

const Page = () => {
return (
<div>
<h1>Try to import and invalid image file</h1>
<Image id="invalid-img" src={test} width={400} height={400} />
</div>
)
}

export default Page
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
@@ -0,0 +1,70 @@
/* eslint-env jest */

import { join } from 'path'
import {
findPort,
getRedboxHeader,
getRedboxSource,
hasRedbox,
killApp,
launchApp,
nextBuild,
} from 'next-test-utils'
import webdriver from 'next-webdriver'

const appDir = join(__dirname, '../')
let appPort: number
let app
let stderr = ''
const msg =
'Error: Image import "../public/invalid.svg" is not a valid image file. The image may be corrupted or an unsupported format.'

function runTests({ isDev }) {
it('should show error', async () => {
if (isDev) {
const browser = await webdriver(appPort, '/')
expect(await hasRedbox(browser)).toBe(true)
expect(await getRedboxHeader(browser)).toBe('Failed to compile')
expect(await getRedboxSource(browser)).toBe(`./pages/index.js:3\n${msg}`)
expect(stderr).toContain(msg)
} else {
expect(stderr).toContain(msg)
}
})
}

describe('Missing Import Image Tests', () => {
describe('dev mode', () => {
beforeAll(async () => {
stderr = ''
appPort = await findPort()
app = await launchApp(appDir, appPort, {
onStderr(msg) {
stderr += msg || ''
},
})
})
afterAll(async () => {
if (app) {
await killApp(app)
}
})

runTests({ isDev: true })
})

describe('server mode', () => {
beforeAll(async () => {
stderr = ''
const result = await nextBuild(appDir, [], { stderr: true })
stderr = result.stderr
})
afterAll(async () => {
if (app) {
await killApp(app)
}
})

runTests({ isDev: false })
})
})