Skip to content

Commit 7e95e30

Browse files
fix: allow certain variable names in development (#33638)
Fixes #24570 A few variable names (listed #24570 (comment)) were causing problems when using `next dev`. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint`
1 parent 0d642f1 commit 7e95e30

File tree

2 files changed

+103
-56
lines changed

2 files changed

+103
-56
lines changed

packages/react-refresh-utils/internal/ReactRefreshModule.runtime.ts

Lines changed: 59 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,70 @@ declare const module: {
1717
// This function gets unwrapped into global scope, which is why we don't invert
1818
// if-blocks. Also, you cannot use `return`.
1919
export default function () {
20-
// Legacy CSS implementations will `eval` browser code in a Node.js context
21-
// to extract CSS. For backwards compatibility, we need to check we're in a
22-
// browser context before continuing.
23-
if (
24-
typeof self !== 'undefined' &&
25-
// AMP / No-JS mode does not inject these helpers:
26-
'$RefreshHelpers$' in self
27-
) {
28-
var currentExports = module.__proto__.exports
29-
var prevExports = module.hot.data?.prevExports ?? null
20+
// Wrapped in an IIFE to avoid polluting the global scope
21+
;(function () {
22+
// Legacy CSS implementations will `eval` browser code in a Node.js context
23+
// to extract CSS. For backwards compatibility, we need to check we're in a
24+
// browser context before continuing.
25+
if (
26+
typeof self !== 'undefined' &&
27+
// AMP / No-JS mode does not inject these helpers:
28+
'$RefreshHelpers$' in self
29+
) {
30+
var currentExports = module.__proto__.exports
31+
var prevExports = module.hot.data?.prevExports ?? null
3032

31-
// This cannot happen in MainTemplate because the exports mismatch between
32-
// templating and execution.
33-
self.$RefreshHelpers$.registerExportsForReactRefresh(
34-
currentExports,
35-
module.id
36-
)
33+
// This cannot happen in MainTemplate because the exports mismatch between
34+
// templating and execution.
35+
self.$RefreshHelpers$.registerExportsForReactRefresh(
36+
currentExports,
37+
module.id
38+
)
3739

38-
// A module can be accepted automatically based on its exports, e.g. when
39-
// it is a Refresh Boundary.
40-
if (self.$RefreshHelpers$.isReactRefreshBoundary(currentExports)) {
41-
// Save the previous exports on update so we can compare the boundary
42-
// signatures.
43-
module.hot.dispose(function (data) {
44-
data.prevExports = currentExports
45-
})
46-
// Unconditionally accept an update to this module, we'll check if it's
47-
// still a Refresh Boundary later.
48-
module.hot.accept()
40+
// A module can be accepted automatically based on its exports, e.g. when
41+
// it is a Refresh Boundary.
42+
if (self.$RefreshHelpers$.isReactRefreshBoundary(currentExports)) {
43+
// Save the previous exports on update so we can compare the boundary
44+
// signatures.
45+
module.hot.dispose(function (data) {
46+
data.prevExports = currentExports
47+
})
48+
// Unconditionally accept an update to this module, we'll check if it's
49+
// still a Refresh Boundary later.
50+
module.hot.accept()
4951

50-
// This field is set when the previous version of this module was a
51-
// Refresh Boundary, letting us know we need to check for invalidation or
52-
// enqueue an update.
53-
if (prevExports !== null) {
54-
// A boundary can become ineligible if its exports are incompatible
55-
// with the previous exports.
56-
//
57-
// For example, if you add/remove/change exports, we'll want to
58-
// re-execute the importing modules, and force those components to
59-
// re-render. Similarly, if you convert a class component to a
60-
// function, we want to invalidate the boundary.
61-
if (
62-
self.$RefreshHelpers$.shouldInvalidateReactRefreshBoundary(
63-
prevExports,
64-
currentExports
65-
)
66-
) {
52+
// This field is set when the previous version of this module was a
53+
// Refresh Boundary, letting us know we need to check for invalidation or
54+
// enqueue an update.
55+
if (prevExports !== null) {
56+
// A boundary can become ineligible if its exports are incompatible
57+
// with the previous exports.
58+
//
59+
// For example, if you add/remove/change exports, we'll want to
60+
// re-execute the importing modules, and force those components to
61+
// re-render. Similarly, if you convert a class component to a
62+
// function, we want to invalidate the boundary.
63+
if (
64+
self.$RefreshHelpers$.shouldInvalidateReactRefreshBoundary(
65+
prevExports,
66+
currentExports
67+
)
68+
) {
69+
module.hot.invalidate()
70+
} else {
71+
self.$RefreshHelpers$.scheduleUpdate()
72+
}
73+
}
74+
} else {
75+
// Since we just executed the code for the module, it's possible that the
76+
// new exports made it ineligible for being a boundary.
77+
// We only care about the case when we were _previously_ a boundary,
78+
// because we already accepted this update (accidental side effect).
79+
var isNoLongerABoundary = prevExports !== null
80+
if (isNoLongerABoundary) {
6781
module.hot.invalidate()
68-
} else {
69-
self.$RefreshHelpers$.scheduleUpdate()
7082
}
7183
}
72-
} else {
73-
// Since we just executed the code for the module, it's possible that the
74-
// new exports made it ineligible for being a boundary.
75-
// We only care about the case when we were _previously_ a boundary,
76-
// because we already accepted this update (accidental side effect).
77-
var isNoLongerABoundary = prevExports !== null
78-
if (isNoLongerABoundary) {
79-
module.hot.invalidate()
80-
}
8184
}
82-
}
85+
})()
8386
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { createNext } from 'e2e-utils'
2+
import { NextInstance } from 'test/lib/next-modes/base'
3+
import { sandbox } from './helpers'
4+
5+
describe('ReactRefreshModule', () => {
6+
let next: NextInstance
7+
8+
beforeAll(async () => {
9+
next = await createNext({
10+
files: {},
11+
skipStart: true,
12+
})
13+
})
14+
afterAll(() => next.destroy())
15+
16+
it('should allow any variable names', async () => {
17+
const { session, cleanup } = await sandbox(next, new Map([]))
18+
expect(await session.hasRedbox()).toBe(false)
19+
20+
const variables = [
21+
'_a',
22+
'_b',
23+
'currentExports',
24+
'prevExports',
25+
'isNoLongerABoundary',
26+
]
27+
28+
for await (const variable of variables) {
29+
await session.patch(
30+
'pages/index.js',
31+
`import { default as ${variable} } from 'next/link'
32+
export default function Page() {
33+
return null
34+
}`
35+
)
36+
expect(await session.hasRedbox()).toBe(false)
37+
expect(next.cliOutput).not.toContain(
38+
`'${variable}' has already been declared`
39+
)
40+
}
41+
42+
await cleanup()
43+
})
44+
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy