first commit
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled

This commit is contained in:
Arian Tron
2026-03-10 19:37:31 +03:30
commit 61f56f997c
27684 changed files with 2784175 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
'use client'
import React from 'react'
import Link from 'next/link'
import { useCallback, useRef, useEffect, useState } from 'react'
import { flushSync } from 'react-dom'
export default function Page() {
const [isVisible, setIsVisible] = useState(true)
const statusRef = useRef({ wasInitialized: false, wasCleanedUp: false })
const refWithCleanup = useCallback((el) => {
if (!el) {
console.error(
'callback refs that returned a cleanup should never be called with null'
)
return
}
statusRef.current.wasInitialized = true
return () => {
statusRef.current.wasCleanedUp = true
}
}, [])
useEffect(() => {
const timeout = setTimeout(
() => {
flushSync(() => {
setIsVisible(false)
})
if (!statusRef.current.wasInitialized) {
console.error('callback ref was not initialized')
}
if (!statusRef.current.wasCleanedUp) {
console.error('callback ref was not cleaned up')
}
},
100 // if we hide the Link too quickly, the prefetch won't fire, failing a test
)
return () => clearTimeout(timeout)
}, [])
if (!isVisible) {
return null
}
return (
<Link href="/" ref={refWithCleanup}>
Click me
</Link>
)
}

View File

@@ -0,0 +1,24 @@
'use client'
import React from 'react'
import Link from 'next/link'
export default () => {
const myRef = React.createRef(null)
React.useEffect(() => {
if (!myRef.current) {
console.error(`ref wasn't updated`)
}
})
return (
<Link
href="/"
ref={(el) => {
myRef.current = el
}}
>
Click me
</Link>
)
}

View File

@@ -0,0 +1,19 @@
'use client'
import React from 'react'
import Link from 'next/link'
export default () => {
const myRef = React.createRef(null)
React.useEffect(() => {
if (!myRef.current) {
console.error(`ref wasn't updated`)
}
})
return (
<Link href="/" ref={myRef}>
Click me
</Link>
)
}

View File

@@ -0,0 +1,15 @@
'use client'
import React from 'react'
import Link from 'next/link'
class MyLink extends React.Component {
render() {
return <span {...this.props}>Click me</span>
}
}
export default () => (
<Link href="/">
<MyLink />
</Link>
)

View File

@@ -0,0 +1,57 @@
'use client'
import React, { useCallback, useEffect, useRef, useState } from 'react'
import Link from 'next/link'
const useClickAway = (ref, onClickAway) => {
useEffect(() => {
const handler = (event) => {
const el = ref.current
// when menu is open and clicked inside menu, A is expected to be false
// when menu is open and clicked outside menu, A is expected to be true
console.log('A', el && !el.contains(event.target))
el && !el.contains(event.target) && onClickAway(event)
}
let timeoutID = setTimeout(() => {
timeoutID = null
document.addEventListener('click', handler)
}, 0)
return () => {
if (timeoutID != null) {
clearTimeout(timeoutID)
}
document.removeEventListener('click', handler)
}
}, [onClickAway, ref])
}
export default function App() {
const [open, setOpen] = useState(false)
const menuRef = useRef(null)
const onClickAway = useCallback(() => {
console.log('click away, open', open)
if (open) {
setOpen(false)
}
}, [open])
useClickAway(menuRef, onClickAway)
return (
<div>
<div id="click-me" onClick={() => setOpen(true)}>
Open Menu
</div>
{open && (
<div ref={menuRef} id="the-menu">
<Link href="/">some link</Link>
</div>
)}
</div>
)
}

View File

@@ -0,0 +1,15 @@
'use client'
import React from 'react'
import Link from 'next/link'
const MyLink = React.forwardRef((props, ref) => (
<span {...props} ref={ref}>
Click me
</span>
))
export default () => (
<Link href="/">
<MyLink />
</Link>
)

View File

@@ -0,0 +1,7 @@
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}

View File

@@ -0,0 +1 @@
export default () => 'hi'

View File

@@ -0,0 +1,132 @@
/* eslint-env jest */
import { join } from 'path'
import webdriver from 'next-webdriver'
import {
retry,
findPort,
launchApp,
killApp,
nextStart,
nextBuild,
waitFor,
} from 'next-test-utils'
let app
let appPort
const appDir = join(__dirname, '..')
const noError = async (pathname) => {
const browser = await webdriver(appPort, '/')
await browser.eval(`(function() {
window.caughtErrors = []
const origError = window.console.error
window.console.error = function (format) {
window.caughtErrors.push(format)
origError(arguments)
}
window.next.router.replace('${pathname}')
})()`)
await waitFor(1000)
const errors = await browser.eval(`window.caughtErrors`)
expect(errors).toEqual([])
await browser.close()
}
const didPrefetch = async (pathname) => {
const requests = []
const browser = await webdriver(appPort, pathname, {
beforePageLoad(page) {
page.on('request', async (req) => {
const url = new URL(req.url())
const headers = await req.allHeaders()
if (headers['next-router-prefetch']) {
requests.push(url.pathname)
}
})
},
})
await browser.waitForIdleNetwork()
await retry(async () => {
expect(requests).toEqual(
expect.arrayContaining([expect.stringContaining('/')])
)
})
await browser.close()
}
function runCommonTests() {
// See https://github.com/vercel/next.js/issues/18437
it('should not have a race condition with a click handler', async () => {
const browser = await webdriver(appPort, '/click-away-race-condition')
await browser.elementByCss('#click-me').click()
await browser.waitForElementByCss('#the-menu')
})
}
describe('Invalid hrefs', () => {
;(process.env.TURBOPACK_BUILD ? describe.skip : describe)(
'development mode',
() => {
beforeAll(async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort)
})
afterAll(() => killApp(app))
runCommonTests()
it('should not show error for function component with forwardRef', async () => {
await noError('/function')
})
it('should not show error for class component as child of next/link', async () => {
await noError('/class')
})
it('should handle child ref with React.createRef', async () => {
await noError('/child-ref')
})
it('should handle child ref that is a function', async () => {
await noError('/child-ref-func')
})
it('should handle child ref that is a function that returns a cleanup function', async () => {
await noError('/child-ref-func-cleanup')
})
}
)
;(process.env.TURBOPACK_DEV ? describe.skip : describe)(
'production mode',
() => {
beforeAll(async () => {
await nextBuild(appDir)
appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))
runCommonTests()
it('should preload with forwardRef', async () => {
await didPrefetch('/function')
})
it('should preload with child ref with React.createRef', async () => {
await didPrefetch('/child-ref')
})
it('should preload with child ref with function', async () => {
await didPrefetch('/child-ref-func')
})
it('should preload with child ref with function that returns a cleanup function', async () => {
await didPrefetch('/child-ref-func-cleanup')
})
}
)
})