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

Use consistent import of vendored React within vendored React #64806

Draft
wants to merge 16 commits into
base: canary
Choose a base branch
from

Conversation

eps1lon
Copy link
Member

@eps1lon eps1lon commented Apr 19, 2024

Required for #64798

The previous import source was incorrect since it resulted in multiple versions of react-dom being bundled. I

  • double check all changed imports
  • Check with ? why we previously didn't do this on purpose
  • check if we can better guard in React or frameworks against multiple versions of React/ReactDOM (it's not just related to our issues but also React Hooks not working: Hooks + multiple instances of React facebook/react#13991)
    For starters, we should stop installing React in our test fixtures and ensure pnpm doesn't auto-install peer deps which it currently does in our test fixtures for unknown reasons.
failing test investigation

test/development/app-dir/edge-errors-hmr/index.test.ts

Reproducible. Unclear how to fix. Build errors are no longer displayed on the client

test/e2e/app-dir/ppr-full/ppr-full.test.ts

Reproducible. Some webpack builds don't seem to alias next/dist/compiled/react-dom to next/dist/server/future/route-modules/app-page/vendored/${layer}/react-dom for unknown reasons.
The case where I tracked it down to was next/dist/server/app-render/rsc/preloads.js resolving ReactDOM to next/dist/compiled/react-dom/index.js instead of next/dist/server/future/route-modules/app-page/vendored/rsc/react-dom.js in the Server bundles.

Closes NEXT-3176

@ijjk ijjk added created-by: Next.js team PRs by the Next.js team type: next labels Apr 19, 2024
@ijjk
Copy link
Member

ijjk commented Apr 19, 2024

Failing test suites

Commit: d206021

__NEXT_EXPERIMENTAL_PPR=true pnpm test-dev test/e2e/app-dir/app-client-cache/client-cache.test.ts (PPR)

  • app dir client cache semantics > should renew the 30s cache once the data is revalidated
Expand output

● app dir client cache semantics › should renew the 30s cache once the data is revalidated

expect(received).toBe(expected) // Object.is equality

Expected: "0.9407366537991813"
Received: "0.6690185802483675"

  35 |
  36 |       // the number should be the same, as we navigated within 30s.
> 37 |       expect(newNumber).toBe(initialNumber)
     |                         ^
  38 |
  39 |       // Fast forward to expire the cache
  40 |       await browser.eval(fastForwardTo, 30 * 1000)

  at Object.toBe (e2e/app-dir/app-client-cache/client-cache.test.ts:37:25)

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-dev test/development/app-dir/missing-required-html-tags/index.test.ts (PPR)

  • app-dir - missing required html tags > should show error overlay
  • app-dir - missing required html tags > should hmr when you fix the error
Expand output

● app-dir - missing required html tags › should show error overlay

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

   8 |     const browser = await next.browser('/')
   9 |
> 10 |     expect(await hasRedbox(browser)).toBe(true)
     |                                      ^
  11 |     expect(await getRedboxDescription(browser)).toMatchInlineSnapshot(`
  12 |       "The following tags are missing in the Root Layout: <html>, <body>.
  13 |       Read more at https://nextjs.org/docs/messages/missing-root-layout-tags"

  at Object.toBe (development/app-dir/missing-required-html-tags/index.test.ts:10:38)

● app-dir - missing required html tags › should hmr when you fix the error

expect(received).toBe(expected) // Object.is equality

Expected: true
Received: false

  22 |     )
  23 |
> 24 |     expect(await hasRedbox(browser)).toBe(true)
     |                                      ^
  25 |     expect(await getRedboxDescription(browser)).toMatchInlineSnapshot(`
  26 |       "The following tags are missing in the Root Layout: <html>.
  27 |       Read more at https://nextjs.org/docs/messages/missing-root-layout-tags"

  at Object.toBe (development/app-dir/missing-required-html-tags/index.test.ts:24:38)

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-dev test/e2e/app-dir/app-basepath/index.test.ts (PPR)

  • app dir - basepath > should only make a single RSC call to the current page (/base/refresh)
  • app dir - basepath > should only make a single RSC call to the current page (/base/refresh?foo=bar)
Expand output

● app dir - basepath › should only make a single RSC call to the current page (/base/refresh)

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

  90 |       await browser.elementByCss('button').click()
  91 |       await retry(async () => {
> 92 |         expect(rscRequests.length).toBe(1)
     |                                    ^
  93 |         expect(rscRequests[0]).toContain(`${next.url}${path}`)
  94 |       })
  95 |     }

  at toBe (e2e/app-dir/app-basepath/index.test.ts:92:36)
  at fn (lib/next-test-utils.ts:774:20)
  at e2e/app-dir/app-basepath/index.test.ts:91:7

● app dir - basepath › should only make a single RSC call to the current page (/base/refresh?foo=bar)

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

  90 |       await browser.elementByCss('button').click()
  91 |       await retry(async () => {
> 92 |         expect(rscRequests.length).toBe(1)
     |                                    ^
  93 |         expect(rscRequests[0]).toContain(`${next.url}${path}`)
  94 |       })
  95 |     }

  at toBe (e2e/app-dir/app-basepath/index.test.ts:92:36)
  at fn (lib/next-test-utils.ts:774:20)
  at e2e/app-dir/app-basepath/index.test.ts:91:7

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-dev test/e2e/app-dir/app-esm-js/index.test.ts (PPR)

  • app-dir - esm js extension > should be able to render nextjs api in app router
Expand output

● app-dir - esm js extension › should be able to render nextjs api in app router

expect(received).toBe(expected) // Object.is equality

Expected: 1
Received: 0

  20 |     await validateDomNodes('#without-ext')
  21 |
> 22 |     expect($('head link[href="/test-ext.js"]').length).toBe(1)
     |                                                        ^
  23 |     expect($('head link[href="/test.js"]').length).toBe(1)
  24 |   })
  25 |

  at Object.toBe (e2e/app-dir/app-esm-js/index.test.ts:22:56)

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-start test/e2e/app-dir/actions-allowed-origins/app-action-allowed-origins.test.ts (PPR)

  • app-dir action allowed origins > should pass if localhost is set as a safe origin
Expand output

● app-dir action allowed origins › should pass if localhost is set as a safe origin

TIMED OUT: hi



undefined

  686 |
  687 |   if (hardError) {
> 688 |     throw new Error('TIMED OUT: ' + regex + '\n\n' + content + '\n\n' + lastErr)
      |           ^
  689 |   }
  690 |   return false
  691 | }

  at check (lib/next-test-utils.ts:688:11)
  at Object.<anonymous> (e2e/app-dir/actions-allowed-origins/app-action-allowed-origins.test.ts:27:5)

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-start test/e2e/app-dir/app/useReportWebVitals.test.ts (PPR)

  • useReportWebVitals hook > should send web-vitals
Expand output

● useReportWebVitals hook › should send web-vitals

TIMED OUT: success

undefined

Error: expect(received).toBeGreaterThanOrEqual(expected)

Expected: >= 6
Received:    0

  686 |
  687 |   if (hardError) {
> 688 |     throw new Error('TIMED OUT: ' + regex + '\n\n' + content + '\n\n' + lastErr)
      |           ^
  689 |   }
  690 |   return false
  691 | }

  at check (lib/next-test-utils.ts:688:11)
  at Object.<anonymous> (e2e/app-dir/app/useReportWebVitals.test.ts:40:5)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-start test/e2e/app-dir/metadata/metadata.test.ts (turbopack)

  • app dir - metadata > basic > should support other basic tags (edge)
Expand output

● app dir - metadata › basic › should support other basic tags (edge)

expect(received).toContain(expected) // indexOf

Expected value: "/preconnect-url"
Received array: []

  36 |           expect(values).not.toContain(undefined)
  37 |         } else {
> 38 |           expect(values).toContain(expected)
     |                          ^
  39 |         }
  40 |       }
  41 |     }

  at toContain (e2e/app-dir/metadata/metadata.test.ts:38:26)
      at async Promise.all (index 2)
  at e2e/app-dir/metadata/metadata.test.ts:133:7
  at Object.<anonymous> (e2e/app-dir/metadata/metadata.test.ts:255:7)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-start test/e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts (turbopack)

  • avoid-popstate-flash > does not flash back to partial PPR data during back/forward navigation
Expand output

● avoid-popstate-flash › does not flash back to partial PPR data during back/forward navigation

thrown: "Exceeded timeout of 60000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

  17 |   })
  18 |
> 19 |   test('does not flash back to partial PPR data during back/forward navigation', async () => {
     |   ^
  20 |     const TestLog = createTestLog()
  21 |     let autoresolveRequests = true
  22 |     let pendingRequests = new Map()

  at test (e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts:19:3)
  at Object.describe (e2e/app-dir/ppr-navigations/avoid-popstate-flash/avoid-popstate-flash.test.ts:6:1)

Read more about building and testing Next.js in contributing.md.

__NEXT_EXPERIMENTAL_PPR=true pnpm test-start test/e2e/app-dir/interception-dynamic-segment-middleware/interception-dynamic-segment-middleware.test.ts (PPR)

  • interception-dynamic-segment-middleware > should work when interception route is paired with a dynamic segment & middleware
Expand output

● interception-dynamic-segment-middleware › should work when interception route is paired with a dynamic segment & middleware

TIMED OUT: /intercepted/



undefined

  686 |
  687 |   if (hardError) {
> 688 |     throw new Error('TIMED OUT: ' + regex + '\n\n' + content + '\n\n' + lastErr)
      |           ^
  689 |   }
  690 |   return false
  691 | }

  at check (lib/next-test-utils.ts:688:11)
  at Object.<anonymous> (e2e/app-dir/interception-dynamic-segment-middleware/interception-dynamic-segment-middleware.test.ts:13:5)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-start test/e2e/app-dir/ppr-full/ppr-full.test.ts (turbopack)

  • ppr-full > Dynamic Data pages > Incidental postpones > should initially render with optimistic UI
  • ppr-full > Dynamic Data pages > Optimistic UI > should initially render with optimistic UI
Expand output

● ppr-full › Dynamic Data pages › Optimistic UI › should initially render with optimistic UI

expect(received).toEqual(expected) // deep equality

Expected: "foo search: bar"
Received: "foo search: optimistic"

  464 |                 'document.getElementById("foosearch").textContent'
  465 |               )
> 466 |             ).toEqual('foo search: bar')
      |               ^
  467 |           } finally {
  468 |             await browser.close()
  469 |           }

  at Object.toEqual (e2e/app-dir/ppr-full/ppr-full.test.ts:466:15)

● ppr-full › Dynamic Data pages › Incidental postpones › should initially render with optimistic UI

expect(received).toEqual(expected) // deep equality

Expected: "foo search: bar"
Received: "foo search: optimistic"

  541 |                 'document.getElementById("foosearch").textContent'
  542 |               )
> 543 |             ).toEqual('foo search: bar')
      |               ^
  544 |           } finally {
  545 |             await browser.close()
  546 |           }

  at Object.toEqual (e2e/app-dir/ppr-full/ppr-full.test.ts:543:15)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-start test/e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts (turbopack)

  • stale-prefetch-entry > works if a prefetched route entry has become stale (too much time has elapsed since it was prefetched)
Expand output

● stale-prefetch-entry › works if a prefetched route entry has become stale (too much time has elapsed since it was prefetched)

thrown: "Exceeded timeout of 60000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

  21 |   // data as if it were complete data that didn't contain dynamic holes. This
  22 |   // prevented the dynamic data from ever streaming in.
> 23 |   test(
     |   ^
  24 |     'works if a prefetched route entry has become stale (too much ' +
  25 |       'time has elapsed since it was prefetched)',
  26 |     async () => {

  at test (e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts:23:3)
  at Object.describe (e2e/app-dir/ppr-navigations/stale-prefetch-entry/stale-prefetch-entry.test.ts:6:1)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-dev test/e2e/app-dir/dynamic/dynamic.test.ts (turbopack)

  • app dir - next/dynamic > no SSR > should not render client component imported through ssr: false in client components in edge runtime
Expand output

● app dir - next/dynamic › no SSR › should not render client component imported through ssr: false in client components in edge runtime

page.waitForSelector: Timeout 60000ms exceeded.
Call log:
  - waiting for locator('#ssr-false-server-module')

  421 |     return this.chain(() => {
  422 |       return page
> 423 |         .waitForSelector(selector, { timeout, state: 'attached' })
      |          ^
  424 |         .then(async (el) => {
  425 |           // it seems selenium waits longer and tests rely on this behavior
  426 |           // so we wait for the load event fire before returning

  at waitForSelector (lib/browsers/playwright.ts:423:10)

Read more about building and testing Next.js in contributing.md.

TURBOPACK=1 pnpm test-start test/e2e/app-dir/taint/process-taint.test.ts (turbopack)

  • app dir - taint > should error when passing process env to client component
Expand output

● app dir - taint › should error when passing process env to client component

thrown: "Exceeded timeout of 60000 ms for a test.
Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."

   5 |
   6 | export function runTest({ next, isNextDev }) {
>  7 |   it('should error when passing process env to client component', async () => {
     |   ^
   8 |     const browser = await next.browser('/')
   9 |     expect(await browser.waitForElementByCss('#error-component').text()).toBe(
  10 |       isNextDev

  at it (e2e/app-dir/taint/process-taint.test.ts:7:3)
  at runTest (e2e/app-dir/taint/process-taint.test.ts:22:3)
  at Object.describe (e2e/app-dir/taint/process-taint.test.ts:17:1)

Read more about building and testing Next.js in contributing.md.

pnpm test-start test/e2e/app-dir/ppr-navigations/loading-tsx-no-partial-rendering/loading-tsx-no-partial-rendering.test.ts

  • loading-tsx-no-partial-rendering > when PPR is enabled, loading.tsx boundaries do not cause a partial prefetch
Expand output

● loading-tsx-no-partial-rendering › when PPR is enabled, loading.tsx boundaries do not cause a partial prefetch

page.waitForSelector: Timeout 60000ms exceeded.
Call log:
  - waiting for locator('a')

  421 |     return this.chain(() => {
  422 |       return page
> 423 |         .waitForSelector(selector, { timeout, state: 'attached' })
      |          ^
  424 |         .then(async (el) => {
  425 |           // it seems selenium waits longer and tests rely on this behavior
  426 |           // so we wait for the load event fire before returning

  at waitForSelector (lib/browsers/playwright.ts:423:10)

Read more about building and testing Next.js in contributing.md.

@ijjk
Copy link
Member

ijjk commented Apr 19, 2024

Stats from current PR

Default Build (Increase detected ⚠️)
General Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
buildDuration 15.8s 14.5s N/A
buildDurationCached 8.6s 7s N/A
nodeModulesSize 360 MB 370 MB ⚠️ +10.1 MB
nextStartRea..uration (ms) 392ms 391ms N/A
Client Bundles (main, webpack)
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
1103-HASH.js gzip 31.8 kB 31.8 kB N/A
1a9f679d-HASH.js gzip 53.5 kB 53.5 kB N/A
335-HASH.js gzip 5.09 kB 5.09 kB N/A
7953.HASH.js gzip 169 B 169 B
framework-HASH.js gzip 45.2 kB 45.2 kB
main-app-HASH.js gzip 231 B 229 B N/A
main-HASH.js gzip 31.5 kB 31.5 kB N/A
webpack-HASH.js gzip 1.65 kB 1.65 kB N/A
Overall change 45.4 kB 45.4 kB
Legacy Client Bundles (polyfills)
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
polyfills-HASH.js gzip 31 kB 31 kB
Overall change 31 kB 31 kB
Client Pages
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
_app-HASH.js gzip 192 B 193 B N/A
_error-HASH.js gzip 192 B 193 B N/A
amp-HASH.js gzip 507 B 511 B N/A
css-HASH.js gzip 341 B 343 B N/A
dynamic-HASH.js gzip 2.52 kB 2.52 kB
edge-ssr-HASH.js gzip 266 B 265 B N/A
head-HASH.js gzip 362 B 365 B N/A
hooks-HASH.js gzip 392 B 392 B
image-HASH.js gzip 4.32 kB 4.32 kB N/A
index-HASH.js gzip 268 B 268 B
link-HASH.js gzip 2.69 kB 2.7 kB N/A
routerDirect..HASH.js gzip 329 B 328 B N/A
script-HASH.js gzip 397 B 397 B
withRouter-HASH.js gzip 324 B 324 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Overall change 4 kB 4 kB
Client Build Manifests
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
_buildManifest.js gzip 483 B 484 B N/A
Overall change 0 B 0 B
Rendered Page Sizes
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
index.html gzip 527 B 527 B
link.html gzip 542 B 541 B N/A
withRouter.html gzip 524 B 524 B
Overall change 1.05 kB 1.05 kB
Edge SSR bundle Size
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
edge-ssr.js gzip 94.7 kB 94.7 kB N/A
page.js gzip 181 kB 179 kB N/A
Overall change 0 B 0 B
Middleware size
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
middleware-b..fest.js gzip 624 B 622 B N/A
middleware-r..fest.js gzip 156 B 156 B
middleware.js gzip 25.7 kB 25.7 kB N/A
edge-runtime..pack.js gzip 839 B 839 B
Overall change 995 B 995 B
Next Runtimes Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
app-page-exp...dev.js gzip 171 kB 264 kB ⚠️ +93.3 kB
app-page-exp..prod.js gzip 98.4 kB 150 kB ⚠️ +51.4 kB
app-page-tur..prod.js gzip 99.9 kB 151 kB ⚠️ +51.4 kB
app-page-tur..prod.js gzip 94.3 kB 94.3 kB
app-page.run...dev.js gzip 157 kB 157 kB
app-page.run..prod.js gzip 93 kB 93 kB
app-route-ex...dev.js gzip 21.5 kB 21.5 kB
app-route-ex..prod.js gzip 15.2 kB 15.2 kB
app-route-tu..prod.js gzip 15.2 kB 15.2 kB
app-route-tu..prod.js gzip 15 kB 15 kB
app-route.ru...dev.js gzip 21.3 kB 21.3 kB
app-route.ru..prod.js gzip 15 kB 15 kB
pages-api-tu..prod.js gzip 9.55 kB 9.55 kB
pages-api.ru...dev.js gzip 9.82 kB 9.82 kB
pages-api.ru..prod.js gzip 9.55 kB 9.55 kB
pages-turbo...prod.js gzip 21.5 kB 21.5 kB
pages.runtim...dev.js gzip 22.1 kB 22.1 kB
pages.runtim..prod.js gzip 21.5 kB 21.5 kB
server.runti..prod.js gzip 51.6 kB 51.6 kB
Overall change 962 kB 1.16 MB ⚠️ +196 kB
build cache Overall increase ⚠️
vercel/next.js canary vercel/next.js sebbie/react-dom-versions Change
0.pack gzip 1.62 MB 1.62 MB ⚠️ +815 B
index.pack gzip 112 kB 116 kB ⚠️ +3.62 kB
Overall change 1.73 MB 1.73 MB ⚠️ +4.44 kB
Diff details
Diff for edge-ssr.js

Diff too large to display

Diff for app-page-exp..ntime.dev.js
failed to diff
Diff for app-page-exp..time.prod.js

Diff too large to display

Diff for app-page-tur..time.prod.js

Diff too large to display

Commit: d206021

@ijjk ijjk added the tests label Apr 20, 2024
@@ -35,6 +35,7 @@ function makeAppAliases(reactChannel = '') {
'react/react.react-server$': `next/dist/compiled/react${reactChannel}/react.react-server`,
'react-dom/server-rendering-stub$': `next/dist/compiled/react-dom${reactChannel}/server-rendering-stub`,
'react-dom$': `next/dist/compiled/react-dom${reactChannel}/server-rendering-stub`,
'next/dist/compiled/react-dom$': `next/dist/compiled/react-dom${reactChannel}/server-rendering-stub`,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming that this is needed to resolve the comment in the taskfile:

// Note that we don't replace react-dom with next/dist/compiled/react-dom
// as it mighe be aliased to the server rendering stub.

@eps1lon eps1lon force-pushed the sebbie/react-dom-versions branch 2 times, most recently from 264a433 to 724c39d Compare April 21, 2024 18:59
@eps1lon eps1lon changed the title Ensure a single react-dom version Ensure a single react-dom version in App Router Apr 23, 2024
@ijjk ijjk added the Turbopack Related to Turbopack with Next.js. label Apr 23, 2024
packages/next/package.json Outdated Show resolved Hide resolved
test/lib/next-modes/base.ts Outdated Show resolved Hide resolved
@eps1lon
Copy link
Member Author

eps1lon commented Apr 25, 2024

Abandoning this for now. Too many hard to debug issues and fbd6174 (#64798) seems to fix the underlying issue as well.

@eps1lon eps1lon closed this Apr 25, 2024
@eps1lon eps1lon deleted the sebbie/react-dom-versions branch April 25, 2024 18:22
It would take precedence over any potential subsequent alias of `next/*` e.g. aliasing `next/dist/compiled/react` to react.react-server
@eps1lon eps1lon restored the sebbie/react-dom-versions branch April 28, 2024 11:43
This reverts commit 4e77092.

We do need it since `next build` just requires `next`.
Every require we do needs to use the vendored React.
We can't rely on bundlers here since `next build` uses default Node.js module resolution.
@eps1lon eps1lon changed the title Ensure a single react-dom version in App Router Use consistent import of vendored React within vendored React Apr 28, 2024
@eps1lon eps1lon reopened this Apr 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
created-by: Next.js team PRs by the Next.js team tests Turbopack Related to Turbopack with Next.js. type: next
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants