Skip to content

Commit 6b527be

Browse files
authored
fix: edge cases for custom react module resolution (#2188)
* fix: use default react resolution for falsy env var * fix: ignore react require hooks that don't resolve * chore: fix eslint complaining * fix: strip query string when matching path for prebundling react * chore: added comment about hook deletion * chore: make require hook error handling more specific * fix: swap require hook forEach orer
1 parent 68daaba commit 6b527be

File tree

2 files changed

+81
-74
lines changed

2 files changed

+81
-74
lines changed
+80-73
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable n/no-extraneous-require, no-underscore-dangle, @typescript-eslint/no-explicit-any */
1+
/* eslint-disable no-underscore-dangle, @typescript-eslint/no-explicit-any */
22

33
// This is a modified version of the require hooks from Next.js
44
// https://github.com/vercel/next.js/blob/b04c70573ac199a9bb3ea42201e0865e610d5b67/packages/next/src/server/require-hook.ts
@@ -11,86 +11,93 @@ const resolveFilename = (mod as any)._resolveFilename
1111
const requireHooks = new Map<string, Map<string, string>>()
1212

1313
export const overrideRequireHooks = (config: NextConfig) => {
14-
// we may have changed the working directory in the handler
15-
const opts = {
16-
paths: [process.cwd()],
17-
}
14+
setRequireHooks(config)
15+
resolveRequireHooks()
16+
}
1817

18+
const setRequireHooks = (config: NextConfig) => {
1919
requireHooks.set(
2020
'default',
2121
new Map([
22-
['react', require.resolve(`react`, opts)],
23-
['react/jsx-runtime', require.resolve(`react/jsx-runtime`, opts)],
22+
['react', `react`],
23+
['react/jsx-runtime', `react/jsx-runtime`],
2424
]),
2525
)
2626

2727
if (config.experimental.appDir) {
28-
requireHooks.set(
29-
'next',
30-
new Map([
31-
['react', require.resolve(`next/dist/compiled/react`, opts)],
32-
['react/jsx-runtime', require.resolve(`next/dist/compiled/react/jsx-runtime`, opts)],
33-
['react/jsx-dev-runtime', require.resolve(`next/dist/compiled/react/jsx-dev-runtime`, opts)],
34-
['react-dom', require.resolve(`next/dist/compiled/react-dom/server-rendering-stub`, opts)],
35-
['react-dom/client', require.resolve(`next/dist/compiled/react-dom/client`, opts)],
36-
['react-dom/server', require.resolve(`next/dist/compiled/react-dom/server`, opts)],
37-
['react-dom/server.browser', require.resolve(`next/dist/compiled/react-dom/server.browser`, opts)],
38-
['react-dom/server.edge', require.resolve(`next/dist/compiled/react-dom/server.edge`, opts)],
39-
[
40-
'react-server-dom-webpack/client',
41-
require.resolve(`next/dist/compiled/react-server-dom-webpack/client`, opts),
42-
],
43-
[
44-
'react-server-dom-webpack/client.edge',
45-
require.resolve(`next/dist/compiled/react-server-dom-webpack/client.edge`, opts),
46-
],
47-
[
48-
'react-server-dom-webpack/server.edge',
49-
require.resolve(`next/dist/compiled/react-server-dom-webpack/server.edge`, opts),
50-
],
51-
[
52-
'react-server-dom-webpack/server.node',
53-
require.resolve(`next/dist/compiled/react-server-dom-webpack/server.node`, opts),
54-
],
55-
['styled-jsx', require.resolve('styled-jsx', opts)],
56-
['styled-jsx/style', require.resolve('styled-jsx/style', opts)],
57-
]),
58-
)
28+
if (config.experimental.serverActions) {
29+
requireHooks.set(
30+
'experimental',
31+
new Map([
32+
['react', `next/dist/compiled/react-experimental`],
33+
['react/jsx-runtime', `next/dist/compiled/react-experimental/jsx-runtime`],
34+
['react/jsx-dev-runtime', `next/dist/compiled/react-experimental/jsx-dev-runtime`],
35+
['react-dom', `next/dist/compiled/react-dom-experimental/server-rendering-stub`],
36+
['react-dom/client', `next/dist/compiled/react-dom-experimental/client`],
37+
['react-dom/server', `next/dist/compiled/react-dom-experimental/server`],
38+
['react-dom/server.browser', `next/dist/compiled/react-dom-experimental/server.browser`],
39+
['react-dom/server.edge', `next/dist/compiled/react-dom-experimental/server.edge`],
40+
['react-server-dom-webpack/client', `next/dist/compiled/react-server-dom-webpack-experimental/client`],
41+
[
42+
'react-server-dom-webpack/client.edge',
43+
`next/dist/compiled/react-server-dom-webpack-experimental/client.edge`,
44+
],
45+
[
46+
'react-server-dom-webpack/server.edge',
47+
`next/dist/compiled/react-server-dom-webpack-experimental/server.edge`,
48+
],
49+
[
50+
'react-server-dom-webpack/server.node',
51+
`next/dist/compiled/react-server-dom-webpack-experimental/server.node`,
52+
],
53+
['styled-jsx', 'styled-jsx'],
54+
['styled-jsx/style', 'styled-jsx/style'],
55+
]),
56+
)
57+
} else {
58+
requireHooks.set(
59+
'next',
60+
new Map([
61+
['react', `next/dist/compiled/react`],
62+
['react/jsx-runtime', `next/dist/compiled/react/jsx-runtime`],
63+
['react/jsx-dev-runtime', `next/dist/compiled/react/jsx-dev-runtime`],
64+
['react-dom', `next/dist/compiled/react-dom/server-rendering-stub`],
65+
['react-dom/client', `next/dist/compiled/react-dom/client`],
66+
['react-dom/server', `next/dist/compiled/react-dom/server`],
67+
['react-dom/server.browser', `next/dist/compiled/react-dom/server.browser`],
68+
['react-dom/server.edge', `next/dist/compiled/react-dom/server.edge`],
69+
['react-server-dom-webpack/client', `next/dist/compiled/react-server-dom-webpack/client`],
70+
['react-server-dom-webpack/client.edge', `next/dist/compiled/react-server-dom-webpack/client.edge`],
71+
['react-server-dom-webpack/server.edge', `next/dist/compiled/react-server-dom-webpack/server.edge`],
72+
['react-server-dom-webpack/server.node', `next/dist/compiled/react-server-dom-webpack/server.node`],
73+
['styled-jsx', 'styled-jsx'],
74+
['styled-jsx/style', 'styled-jsx/style'],
75+
]),
76+
)
77+
}
5978
}
79+
}
6080

61-
if (config.experimental.serverActions) {
62-
requireHooks.set(
63-
'experimental',
64-
new Map([
65-
['react', require.resolve(`next/dist/compiled/react-experimental`, opts)],
66-
['react/jsx-runtime', require.resolve(`next/dist/compiled/react-experimental/jsx-runtime`, opts)],
67-
['react/jsx-dev-runtime', require.resolve(`next/dist/compiled/react-experimental/jsx-dev-runtime`, opts)],
68-
['react-dom', require.resolve(`next/dist/compiled/react-dom-experimental/server-rendering-stub`, opts)],
69-
['react-dom/client', require.resolve(`next/dist/compiled/react-dom-experimental/client`, opts)],
70-
['react-dom/server', require.resolve(`next/dist/compiled/react-dom-experimental/server`, opts)],
71-
['react-dom/server.browser', require.resolve(`next/dist/compiled/react-dom-experimental/server.browser`, opts)],
72-
['react-dom/server.edge', require.resolve(`next/dist/compiled/react-dom-experimental/server.edge`, opts)],
73-
[
74-
'react-server-dom-webpack/client',
75-
require.resolve(`next/dist/compiled/react-server-dom-webpack-experimental/client`, opts),
76-
],
77-
[
78-
'react-server-dom-webpack/client.edge',
79-
require.resolve(`next/dist/compiled/react-server-dom-webpack-experimental/client.edge`, opts),
80-
],
81-
[
82-
'react-server-dom-webpack/server.edge',
83-
require.resolve(`next/dist/compiled/react-server-dom-webpack-experimental/server.edge`, opts),
84-
],
85-
[
86-
'react-server-dom-webpack/server.node',
87-
require.resolve(`next/dist/compiled/react-server-dom-webpack-experimental/server.node`, opts),
88-
],
89-
['styled-jsx', require.resolve('styled-jsx', opts)],
90-
['styled-jsx/style', require.resolve('styled-jsx/style', opts)],
91-
]),
92-
)
93-
}
81+
const resolveRequireHooks = () => {
82+
// we may have changed the working directory in the handler
83+
const opts = { paths: [process.cwd()] }
84+
85+
// resolve require hooks with module paths
86+
requireHooks.forEach((mode) => {
87+
mode.forEach((path, hook) => {
88+
try {
89+
const resolvedPath = require.resolve(path, opts)
90+
mode.set(hook, resolvedPath)
91+
} catch (error) {
92+
if (error.code === 'MODULE_NOT_FOUND') {
93+
// module not present (older version of Next.js)
94+
mode.delete(hook)
95+
} else {
96+
throw error
97+
}
98+
}
99+
})
100+
})
94101
}
95102

96103
export const applyRequireHooks = () => {
@@ -103,12 +110,12 @@ export const applyRequireHooks = () => {
103110
isMain: boolean,
104111
options: any,
105112
) {
106-
const reactMode = process.env.__NEXT_PRIVATE_PREBUNDLED_REACT ?? 'default'
113+
const reactMode = process.env.__NEXT_PRIVATE_PREBUNDLED_REACT || 'default'
107114
const resolvedRequest = hooks.get(reactMode)?.get(request) ?? request
108115

109116
return originalResolveFilename.call(mod, resolvedRequest, parent, isMain, options)
110117

111118
// We use `bind` here to avoid referencing outside variables to create potential memory leaks.
112119
}.bind(null, resolveFilename, requireHooks)
113120
}
114-
/* eslint-enable n/no-extraneous-require, no-underscore-dangle, @typescript-eslint/no-explicit-any */
121+
/* eslint-enable no-underscore-dangle, @typescript-eslint/no-explicit-any */

packages/runtime/src/templates/server.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ const getNetlifyNextServer = (NextServer: NextServerType) => {
8181
const appPathsManifest = this.getAppPathsManifest?.()
8282

8383
const routes = routesManifest && [...routesManifest.staticRoutes, ...routesManifest.dynamicRoutes]
84-
const matchedRoute = routes?.find((route) => new RegExp(route.regex).test(path))
84+
const matchedRoute = routes?.find((route) => new RegExp(route.regex).test(path.split('?')[0]))
8585
const isAppRoute =
8686
appPathsManifest && matchedRoute ? appPathsManifest[joinPaths(matchedRoute.page, 'page')] : false
8787

0 commit comments

Comments
 (0)