Skip to content

Commit

Permalink
fix(next/image): don't call ReactDOM.preload if missing, such as jest (
Browse files Browse the repository at this point in the history
…#53443)

### What?

`ReactDOM.preload` is available in `react-dom@experimental` builds. If it's not available, we should fall back to `Head`+`link`

### Why?

Since `ReactDOM.preload` is only available in `react-dom@experimental` builds, certain environments (like Jest or [Storybook](storybookjs/storybook#23661)) might have a version of `react-dom` installed that won't work with `preload()`

### How?

Closes NEXT-1482
Fixes #53272

See also: storybookjs/storybook#23661

Co-authored-by: Steven <229881+styfle@users.noreply.github.com>
  • Loading branch information
balazsorban44 and styfle authored Aug 8, 2023
1 parent c669c38 commit b41497d
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/next/src/client/image-component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ function ImagePreload({
...getDynamicProps(imgAttributes.fetchPriority),
}

if (isAppRouter) {
if (isAppRouter && preload) {
// See https://github.com/facebook/react/pull/26940
preload(
imgAttributes.src,
Expand Down
12 changes: 12 additions & 0 deletions test/production/jest/next-image-preload/app/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
1 change: 1 addition & 0 deletions test/production/jest/next-image-preload/app/app/next.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions test/production/jest/next-image-preload/app/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'
import Image from 'next/image'
import logo from './next.svg'

export default function MyImage() {
return <Image alt="" src={logo} priority />
}
16 changes: 16 additions & 0 deletions test/production/jest/next-image-preload/app/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const nextJest = require('next/jest')

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: './',
})

// Add any custom config to be passed to Jest
const customJestConfig = {
// if using TypeScript with a baseUrl set to the root directory then you need the below for alias' to work
moduleDirectories: ['node_modules', '<rootDir>/'],
testEnvironment: 'jest-environment-jsdom',
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
module.exports = createJestConfig(customJestConfig)
50 changes: 50 additions & 0 deletions test/production/jest/next-image-preload/next-image-preload.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { createNext, FileRef } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import path from 'path'
import execa from 'execa'

const appDir = path.join(__dirname, 'app')

describe('next/jest', () => {
let next: NextInstance

beforeAll(async () => {
next = await createNext({
skipStart: true,
files: {
app: new FileRef(path.join(appDir, 'app')),
[`tests/index.test.tsx`]: `
import { render, screen } from '@testing-library/react'
import Page from '../app/page'
it('<Page /> renders', () => {
render(<Page />)
const logo = screen.getByRole('img')
expect(logo).toBeDefined()
})
`,
'jest.config.js': new FileRef(path.join(appDir, 'jest.config.js')),
},
dependencies: {
jest: '29.6.2',
'jest-environment-jsdom': '29.6.2',
'@testing-library/react': '14.0.0',
'@testing-library/jest-dom': '5.17.0',
},
})
})
afterAll(() => next.destroy())

it('Should not throw preload is undefined error', async () => {
const { stdout, stderr } = await execa(
'pnpm',
['jest', 'tests/index.test.tsx'],
{
cwd: next.testDir,
reject: false,
}
)
// Uncaught [TypeError: (0 , _reactdom.preload) is not a function]
expect(stdout + stderr).not.toContain('is not a function')
})
})

0 comments on commit b41497d

Please sign in to comment.