Fix extra swc optimizer applied to node_modules in browser layer (#62051)

### What

Disable swc transform optimizer for node_modules in browser layer of app
router bundles

Fixes #61858
Fixes #60644 
Fixes #60920
Fixes #61740
Closes NEXT-2418

### Why

In browser there could be not only one runtime, it could have both js
worker and browser. In js worker the `typeof window` is not as same as
in browser, so disabling the swc optimizer which will replace the code.
Leave the condition as it as.
This commit is contained in:
Jiachi Liu 2024-02-14 21:58:39 +01:00 committed by GitHub
parent 9559e440f4
commit cfedc529c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 58 additions and 2 deletions

View file

@ -482,6 +482,11 @@ export function getLoaderSWCOptions({
options.isPageFile = false options.isPageFile = false
options.optimizeServerReact = undefined options.optimizeServerReact = undefined
options.cjsRequireOptimizer = undefined options.cjsRequireOptimizer = undefined
// Disable optimizer for node_modules in app browser layer, to avoid unnecessary replacement.
// e.g. typeof window could result differently in js worker or browser.
if (options.jsc.transform.optimizer.globals?.typeofs) {
delete options.jsc.transform.optimizer.globals.typeofs.window
}
} }
return options return options

View file

@ -1,5 +1,5 @@
import { createNextDescribe } from 'e2e-utils' import { createNextDescribe } from 'e2e-utils'
import { check, hasRedbox, shouldRunTurboDevTest } from 'next-test-utils' import { check, hasRedbox, retry, shouldRunTurboDevTest } from 'next-test-utils'
async function resolveStreamResponse(response: any, onData?: any) { async function resolveStreamResponse(response: any, onData?: any) {
let result = '' let result = ''
@ -153,6 +153,19 @@ createNextDescribe(
).toMatch(/^__myFont_.{6}, __myFont_Fallback_.{6}$/) ).toMatch(/^__myFont_.{6}, __myFont_Fallback_.{6}$/)
}) })
it('should not apply swc optimizer transform for external packages in browser layer', async () => {
const browser = await next.browser('/browser')
expect(await browser.elementByCss('#worker-state').text()).toBe('default')
await browser.elementByCss('button').click()
await retry(async () => {
expect(await browser.elementByCss('#worker-state').text()).toBe(
'worker.js:browser-module/other'
)
})
})
describe('react in external esm packages', () => { describe('react in external esm packages', () => {
it('should use the same react in client app', async () => { it('should use the same react in client app', async () => {
const html = await next.render('/esm/client') const html = await next.render('/esm/client')

View file

@ -0,0 +1,22 @@
'use client'
import { useState } from 'react'
export default function Home() {
const [state, setState] = useState('default')
return (
<div>
<button
onClick={() => {
const worker = new Worker(new URL('./worker', import.meta.url))
worker.addEventListener('message', (event) => {
setState(event.data)
})
}}
>
Get web worker data
</button>
<p>Worker state: </p>
<p id="worker-state">{state}</p>
</div>
)
}

View file

@ -0,0 +1,3 @@
import { value } from 'browser-module'
self.postMessage('worker.js:' + value)

View file

@ -0,0 +1,4 @@
'use client'
export const value =
'browser-module/' + (typeof window !== 'undefined' ? 'browser' : 'other')

View file

@ -0,0 +1 @@
export const value = 'browser-module/index'

View file

@ -0,0 +1,7 @@
{
"type": "module",
"exports": {
"browser": "./browser.js",
"default": "./index.js"
}
}

View file

@ -2567,7 +2567,8 @@
], ],
"failed": [ "failed": [
"app dir - external dependency server actions should compile server actions from node_modules in client components", "app dir - external dependency server actions should compile server actions from node_modules in client components",
"app dir - external dependency should be able to opt-out 3rd party packages being bundled in server components" "app dir - external dependency should be able to opt-out 3rd party packages being bundled in server components",
"app dir - external dependency should not apply swc optimizer transform for external packages in browser layer"
], ],
"pending": [], "pending": [],
"flakey": [], "flakey": [],