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 next/image default loader errors #18152

Merged
merged 10 commits into from Oct 25, 2020
6 changes: 6 additions & 0 deletions packages/next/build/webpack-config.ts
Expand Up @@ -994,6 +994,12 @@ export default async function getBaseWebpackConfig(
sizes: config.images.sizes,
path: config.images.path,
loader: config.images.loader,
...(dev
? {
// pass domains in development to allow validating on the client
domains: config.images.domains,
}
: {}),
}),
'process.env.__NEXT_ROUTER_BASEPATH': JSON.stringify(config.basePath),
'process.env.__NEXT_HAS_REWRITES': JSON.stringify(hasRewrites),
Expand Down
44 changes: 43 additions & 1 deletion packages/next/client/image.tsx
Expand Up @@ -17,6 +17,7 @@ type ImageData = {
sizes: number[]
loader: LoaderKey
path: string
domains?: string[]
}

type ImageProps = Omit<
Expand All @@ -34,7 +35,12 @@ type ImageProps = Omit<
)

const imageData: ImageData = process.env.__NEXT_IMAGE_OPTS as any
const { sizes: configSizes, loader: configLoader, path: configPath } = imageData
const {
sizes: configSizes,
loader: configLoader,
path: configPath,
domains: configDomains,
} = imageData
configSizes.sort((a, b) => a - b) // smallest to largest
const largestSize = configSizes[configSizes.length - 1]

Expand Down Expand Up @@ -349,6 +355,42 @@ function cloudinaryLoader({ root, src, width, quality }: LoaderProps): string {
}

function defaultLoader({ root, src, width, quality }: LoaderProps): string {
if (process.env.NODE_ENV !== 'production') {
const missingValues = []

// these should always be provided but make sure they are
if (!src) missingValues.push('src')
if (!width) missingValues.push('width')

if (missingValues.length > 0) {
throw new Error(
`Next Image Optimization requires ${missingValues.join(
', '
)} to be provided. Make sure you pass them as props to the \`next/image\` component. Received: ${JSON.stringify(
{ src, width, quality }
)}`
)
}

if (src && !src.startsWith('/') && configDomains) {
let parsedSrc: URL
try {
parsedSrc = new URL(src)
} catch (err) {
console.error(err)
throw new Error(
`Failed to parse "${src}" if using relative image it must start with a leading slash "/" or be an absolute URL`
)
}

if (!configDomains.includes(parsedSrc.hostname)) {
throw new Error(
`Invalid src prop (${src}) on \`next/image\`, hostname is not configured under images in your \`next.config.js\``
)
}
}
}

return `${root}?url=${encodeURIComponent(src)}&w=${width}&q=${
quality || '100'
}`
Expand Down
13 changes: 13 additions & 0 deletions test/integration/image-component/default/pages/invalid-src.js
@@ -0,0 +1,13 @@
import React from 'react'
import Image from 'next/image'

const Page = () => {
return (
<div>
<p>Hello World</p>
<Image src="https://google.com/test.png" unsized></Image>
</div>
)
}

export default Page
12 changes: 12 additions & 0 deletions test/integration/image-component/default/pages/missing-src.js
@@ -0,0 +1,12 @@
import React from 'react'
import Image from 'next/image'

const Page = () => {
return (
<div>
<Image width={200}></Image>
</div>
)
}

export default Page
24 changes: 23 additions & 1 deletion test/integration/image-component/default/test/index.test.js
Expand Up @@ -8,6 +8,8 @@ import {
nextStart,
nextBuild,
check,
hasRedbox,
getRedboxHeader,
} from 'next-test-utils'
import webdriver from 'next-webdriver'
import fs from 'fs-extra'
Expand All @@ -20,7 +22,7 @@ const nextConfig = join(appDir, 'next.config.js')
let appPort
let app

function runTests() {
function runTests(mode) {
it('should load the images', async () => {
let browser
try {
Expand Down Expand Up @@ -79,6 +81,26 @@ function runTests() {
}
}
})

if (mode === 'dev') {
it('should show missing src error', async () => {
const browser = await webdriver(appPort, '/missing-src')

await hasRedbox(browser)
expect(await getRedboxHeader(browser)).toContain(
'Next Image Optimization requires src to be provided. Make sure you pass them as props to the `next/image` component. Received: {"width":1200}'
)
})

it('should show invalid src error', async () => {
const browser = await webdriver(appPort, '/invalid-src')

await hasRedbox(browser)
expect(await getRedboxHeader(browser)).toContain(
'Invalid src prop (https://google.com/test.png) on `next/image`, hostname is not configured under images in your `next.config.js`'
)
})
}
}

describe('Image Component Tests', () => {
Expand Down