@samitouri / QOS-React-2 / commits / 274b9fb168

Remove path resolution from internal forks plugin (#23255)

Alternative to #23254 Our build script has a custom plugin to resolve internal module forks. Currently, it uses require.resolve to resolve the path to a real file on disk. Instead, I've updated all the forked module paths to match their location on disk, relative to the project root, to remove the need to resolve them in the build script's runtime. The main motivation is because require.resolve doesn't work with ESM modules, but aside from that, hardcoding the relative paths is more predictable — the Node module resolution algorithm is complicated, and we don't really need its features for this purpose.

Andrew Clark committed Feb 9, 2022 at 08:44 UTC 274b9fb168eae1b3e5b83db657eb964d365fc45a
2 files changed +100 -65
scripts/rollup/forks.js
+94 -63
@@ -30,10 +30,22 @@ const __EXPERIMENTAL__ =
30
31 // If you need to replace a file with another file for a specific environment,
32 // add it to this list with the logic for choosing the right replacement.
33 +
34 +// Fork paths are relative to the project root. They must include the full path,
35 +// including the extension. We intentionally don't use Node's module resolution
36 +// algorithm because 1) require.resolve doesn't work with ESM modules, and 2)
37 +// the behavior is easier to predict.
38 const forks = Object.freeze({
39 // Optimization: for UMDs, use a version that we can inline into the React bundle.
40 // Use that from all other bundles.
36 - 'object-assign': (bundleType, entry, dependencies) => {
41 +
42 + // NOTE: This is hard-coded to the main entry point of the (third-party)
43 + // object-assign package.
44 + './node_modules/object-assign/index.js': (
45 + bundleType,
46 + entry,
47 + dependencies
48 + ) => {
49 if (
50 bundleType !== UMD_DEV &&
51 bundleType !== UMD_PROD &&
@@ -45,7 +57,7 @@ const forks = Object.freeze({
57 }
58 if (entry === 'react' || entry === 'react/unstable-shared-subset') {
59 // Use the forked version that uses ES modules instead of CommonJS.
48 - return 'shared/forks/object-assign.inline-umd.js';
60 + return './packages/shared/forks/object-assign.inline-umd.js';
61 }
62 if (dependencies.indexOf('react') === -1) {
63 // We can only apply the optimizations to bundle that depend on React
@@ -53,19 +65,25 @@ const forks = Object.freeze({
65 return null;
66 }
67 // We can use the fork that reads the secret export!
56 - return 'shared/forks/object-assign.umd.js';
68 + return './packages/shared/forks/object-assign.umd.js';
69 },
70
59 - 'react-shallow-renderer': () => {
71 + // NOTE: This is hard-coded to the main entry point of the (third-party)
72 + // react-shallow-renderer package.
73 + './node_modules/react-shallow-renderer/index.js': () => {
74 // Use ESM build of `react-shallow-renderer`.
61 - return 'react-shallow-renderer/esm/index.js';
75 + return './node_modules/react-shallow-renderer/esm/index.js';
76 },
77
78 // Without this fork, importing `shared/ReactSharedInternals` inside
79 // the `react` package itself would not work due to a cyclical dependency.
66 - 'shared/ReactSharedInternals': (bundleType, entry, dependencies) => {
80 + './packages/shared/ReactSharedInternals.js': (
81 + bundleType,
82 + entry,
83 + dependencies
84 + ) => {
85 if (entry === 'react' || entry === 'react/unstable-shared-subset') {
68 - return 'react/src/ReactSharedInternals.js';
86 + return './packages/react/src/ReactSharedInternals.js';
87 }
88 if (!entry.startsWith('react/') && dependencies.indexOf('react') === -1) {
89 // React internals are unavailable if we can't reference the package.
@@ -82,18 +100,18 @@ const forks = Object.freeze({
100 },
101
102 // We have a few forks for different environments.
85 - 'shared/ReactFeatureFlags': (bundleType, entry) => {
103 + './packages/shared/ReactFeatureFlags.js': (bundleType, entry) => {
104 switch (entry) {
105 case 'react-native-renderer':
106 switch (bundleType) {
107 case RN_FB_DEV:
108 case RN_FB_PROD:
109 case RN_FB_PROFILING:
92 - return 'shared/forks/ReactFeatureFlags.native-fb.js';
110 + return './packages/shared/forks/ReactFeatureFlags.native-fb.js';
111 case RN_OSS_DEV:
112 case RN_OSS_PROD:
113 case RN_OSS_PROFILING:
96 - return 'shared/forks/ReactFeatureFlags.native-oss.js';
114 + return './packages/shared/forks/ReactFeatureFlags.native-oss.js';
115 default:
116 throw Error(
117 `Unexpected entry (${entry}) and bundleType (${bundleType})`
@@ -104,11 +122,11 @@ const forks = Object.freeze({
122 case RN_FB_DEV:
123 case RN_FB_PROD:
124 case RN_FB_PROFILING:
107 - return 'shared/forks/ReactFeatureFlags.native-fb.js';
125 + return './packages/shared/forks/ReactFeatureFlags.native-fb.js';
126 case RN_OSS_DEV:
127 case RN_OSS_PROD:
128 case RN_OSS_PROFILING:
111 - return 'shared/forks/ReactFeatureFlags.native-oss.js';
129 + return './packages/shared/forks/ReactFeatureFlags.native-oss.js';
130 default:
131 throw Error(
132 `Unexpected entry (${entry}) and bundleType (${bundleType})`
@@ -122,37 +140,37 @@ const forks = Object.freeze({
140 case RN_OSS_DEV:
141 case RN_OSS_PROD:
142 case RN_OSS_PROFILING:
125 - return 'shared/forks/ReactFeatureFlags.test-renderer.native.js';
143 + return './packages/shared/forks/ReactFeatureFlags.test-renderer.native.js';
144 case FB_WWW_DEV:
145 case FB_WWW_PROD:
146 case FB_WWW_PROFILING:
129 - return 'shared/forks/ReactFeatureFlags.test-renderer.www.js';
147 + return './packages/shared/forks/ReactFeatureFlags.test-renderer.www.js';
148 }
131 - return 'shared/forks/ReactFeatureFlags.test-renderer.js';
149 + return './packages/shared/forks/ReactFeatureFlags.test-renderer.js';
150 case 'react-dom/unstable_testing':
151 switch (bundleType) {
152 case FB_WWW_DEV:
153 case FB_WWW_PROD:
154 case FB_WWW_PROFILING:
137 - return 'shared/forks/ReactFeatureFlags.testing.www.js';
155 + return './packages/shared/forks/ReactFeatureFlags.testing.www.js';
156 }
139 - return 'shared/forks/ReactFeatureFlags.testing.js';
157 + return './packages/shared/forks/ReactFeatureFlags.testing.js';
158 default:
159 switch (bundleType) {
160 case FB_WWW_DEV:
161 case FB_WWW_PROD:
162 case FB_WWW_PROFILING:
145 - return 'shared/forks/ReactFeatureFlags.www.js';
163 + return './packages/shared/forks/ReactFeatureFlags.www.js';
164 case RN_FB_DEV:
165 case RN_FB_PROD:
166 case RN_FB_PROFILING:
149 - return 'shared/forks/ReactFeatureFlags.native-fb.js';
167 + return './packages/shared/forks/ReactFeatureFlags.native-fb.js';
168 }
169 }
170 return null;
171 },
172
155 - scheduler: (bundleType, entry, dependencies) => {
173 + './packages/scheduler/index.js': (bundleType, entry, dependencies) => {
174 switch (bundleType) {
175 case UMD_DEV:
176 case UMD_PROD:
@@ -164,28 +182,32 @@ const forks = Object.freeze({
182 }
183 // Optimization: for UMDs, use the API that is already a part of the React
184 // package instead of requiring it to be loaded via a separate <script> tag
167 - return 'shared/forks/Scheduler.umd.js';
185 + return './packages/shared/forks/Scheduler.umd.js';
186 default:
187 // For other bundles, use the shared NPM package.
188 return null;
189 }
190 },
191
174 - 'scheduler/src/SchedulerFeatureFlags': (bundleType, entry, dependencies) => {
192 + './packages/scheduler/src/SchedulerFeatureFlags.js': (
193 + bundleType,
194 + entry,
195 + dependencies
196 + ) => {
197 if (
198 bundleType === FB_WWW_DEV ||
199 bundleType === FB_WWW_PROD ||
200 bundleType === FB_WWW_PROFILING
201 ) {
180 - return 'scheduler/src/forks/SchedulerFeatureFlags.www.js';
202 + return './packages/scheduler/src/forks/SchedulerFeatureFlags.www.js';
203 }
182 - return 'scheduler/src/SchedulerFeatureFlags';
204 + return './packages/scheduler/src/SchedulerFeatureFlags.js';
205 },
206
185 - 'shared/consoleWithStackDev': (bundleType, entry) => {
207 + './packages/shared/consoleWithStackDev.js': (bundleType, entry) => {
208 switch (bundleType) {
209 case FB_WWW_DEV:
188 - return 'shared/forks/consoleWithStackDev.www.js';
210 + return './packages/shared/forks/consoleWithStackDev.www.js';
211 default:
212 return null;
213 }
@@ -193,12 +215,12 @@ const forks = Object.freeze({
215
216 // In FB bundles, we preserve an inline require to ReactCurrentOwner.
217 // See the explanation in FB version of ReactCurrentOwner in www:
196 - 'react/src/ReactCurrentOwner': (bundleType, entry) => {
218 + './packages/react/src/ReactCurrentOwner.js': (bundleType, entry) => {
219 switch (bundleType) {
220 case FB_WWW_DEV:
221 case FB_WWW_PROD:
222 case FB_WWW_PROFILING:
201 - return 'react/src/forks/ReactCurrentOwner.www.js';
223 + return './packages/react/src/forks/ReactCurrentOwner.www.js';
224 default:
225 return null;
226 }
@@ -206,41 +228,41 @@ const forks = Object.freeze({
228
229 // Similarly, we preserve an inline require to ReactCurrentDispatcher.
230 // See the explanation in FB version of ReactCurrentDispatcher in www:
209 - 'react/src/ReactCurrentDispatcher': (bundleType, entry) => {
231 + './packages/react/src/ReactCurrentDispatcher.js': (bundleType, entry) => {
232 switch (bundleType) {
233 case FB_WWW_DEV:
234 case FB_WWW_PROD:
235 case FB_WWW_PROFILING:
214 - return 'react/src/forks/ReactCurrentDispatcher.www.js';
236 + return './packages/react/src/forks/ReactCurrentDispatcher.www.js';
237 default:
238 return null;
239 }
240 },
241
220 - 'react/src/ReactSharedInternals.js': (bundleType, entry) => {
242 + './packages/react/src/ReactSharedInternals.js': (bundleType, entry) => {
243 switch (bundleType) {
244 case UMD_DEV:
245 case UMD_PROD:
246 case UMD_PROFILING:
225 - return 'react/src/forks/ReactSharedInternals.umd.js';
247 + return './packages/react/src/forks/ReactSharedInternals.umd.js';
248 default:
249 return null;
250 }
251 },
252
253 // Different wrapping/reporting for caught errors.
232 - 'shared/invokeGuardedCallbackImpl': (bundleType, entry) => {
254 + './packages/shared/invokeGuardedCallbackImpl.js': (bundleType, entry) => {
255 switch (bundleType) {
256 case FB_WWW_DEV:
257 case FB_WWW_PROD:
258 case FB_WWW_PROFILING:
237 - return 'shared/forks/invokeGuardedCallbackImpl.www.js';
259 + return './packages/shared/forks/invokeGuardedCallbackImpl.www.js';
260 default:
261 return null;
262 }
263 },
264
243 - 'react-reconciler/src/ReactFiberReconciler': (
265 + './packages/react-reconciler/src/ReactFiberReconciler.js': (
266 bundleType,
267 entry,
268 dependencies,
@@ -253,14 +275,14 @@ const forks = Object.freeze({
275 case FB_WWW_PROD:
276 case FB_WWW_PROFILING:
277 // Use the forked version of the reconciler
256 - return 'react-reconciler/src/ReactFiberReconciler.new.js';
278 + return './packages/react-reconciler/src/ReactFiberReconciler.new.js';
279 }
280 }
281 // Otherwise, use the non-forked version.
260 - return 'react-reconciler/src/ReactFiberReconciler.old.js';
282 + return './packages/react-reconciler/src/ReactFiberReconciler.old.js';
283 },
284
263 - 'react-reconciler/src/ReactEventPriorities': (
285 + './packages/react-reconciler/src/ReactEventPriorities.js': (
286 bundleType,
287 entry,
288 dependencies,
@@ -273,14 +295,14 @@ const forks = Object.freeze({
295 case FB_WWW_PROD:
296 case FB_WWW_PROFILING:
297 // Use the forked version of the reconciler
276 - return 'react-reconciler/src/ReactEventPriorities.new.js';
298 + return './packages/react-reconciler/src/ReactEventPriorities.new.js';
299 }
300 }
301 // Otherwise, use the non-forked version.
280 - return 'react-reconciler/src/ReactEventPriorities.old.js';
302 + return './packages/react-reconciler/src/ReactEventPriorities.old.js';
303 },
304
283 - 'react-reconciler/src/ReactFiberHotReloading': (
305 + './packages/react-reconciler/src/ReactFiberHotReloading.js': (
306 bundleType,
307 entry,
308 dependencies,
@@ -293,21 +315,24 @@ const forks = Object.freeze({
315 case FB_WWW_PROD:
316 case FB_WWW_PROFILING:
317 // Use the forked version of the reconciler
296 - return 'react-reconciler/src/ReactFiberHotReloading.new.js';
318 + return './packages/react-reconciler/src/ReactFiberHotReloading.new.js';
319 }
320 }
321 // Otherwise, use the non-forked version.
300 - return 'react-reconciler/src/ReactFiberHotReloading.old.js';
322 + return './packages/react-reconciler/src/ReactFiberHotReloading.old.js';
323 },
324
325 // Different dialogs for caught errors.
304 - 'react-reconciler/src/ReactFiberErrorDialog': (bundleType, entry) => {
326 + './packages/react-reconciler/src/ReactFiberErrorDialog.js': (
327 + bundleType,
328 + entry
329 + ) => {
330 switch (bundleType) {
331 case FB_WWW_DEV:
332 case FB_WWW_PROD:
333 case FB_WWW_PROFILING:
334 // Use the www fork which shows an error dialog.
310 - return 'react-reconciler/src/forks/ReactFiberErrorDialog.www.js';
335 + return './packages/react-reconciler/src/forks/ReactFiberErrorDialog.www.js';
336 case RN_OSS_DEV:
337 case RN_OSS_PROD:
338 case RN_OSS_PROFILING:
@@ -318,7 +343,7 @@ const forks = Object.freeze({
343 case 'react-native-renderer':
344 case 'react-native-renderer/fabric':
345 // Use the RN fork which plays well with redbox.
321 - return 'react-reconciler/src/forks/ReactFiberErrorDialog.native.js';
346 + return './packages/react-reconciler/src/forks/ReactFiberErrorDialog.native.js';
347 default:
348 return null;
349 }
@@ -327,7 +352,7 @@ const forks = Object.freeze({
352 }
353 },
354
330 - 'react-reconciler/src/ReactFiberHostConfig': (
355 + './packages/react-reconciler/src/ReactFiberHostConfig.js': (
356 bundleType,
357 entry,
358 dependencies,
@@ -342,7 +367,7 @@ const forks = Object.freeze({
367 // eslint-disable-next-line no-for-of-loops/no-for-of-loops
368 for (let rendererInfo of inlinedHostConfigs) {
369 if (rendererInfo.entryPoints.indexOf(entry) !== -1) {
345 - return `react-reconciler/src/forks/ReactFiberHostConfig.${rendererInfo.shortName}.js`;
370 + return `./packages/react-reconciler/src/forks/ReactFiberHostConfig.${rendererInfo.shortName}.js`;
371 }
372 }
373 throw new Error(
@@ -352,7 +377,7 @@ const forks = Object.freeze({
377 );
378 },
379
355 - 'react-server/src/ReactServerStreamConfig': (
380 + './packages/react-server/src/ReactServerStreamConfig.js': (
381 bundleType,
382 entry,
383 dependencies,
@@ -370,7 +395,7 @@ const forks = Object.freeze({
395 if (!rendererInfo.isServerSupported) {
396 return null;
397 }
373 - return `react-server/src/forks/ReactServerStreamConfig.${rendererInfo.shortName}.js`;
398 + return `./packages/react-server/src/forks/ReactServerStreamConfig.${rendererInfo.shortName}.js`;
399 }
400 }
401 throw new Error(
@@ -380,7 +405,7 @@ const forks = Object.freeze({
405 );
406 },
407
383 - 'react-server/src/ReactServerFormatConfig': (
408 + './packages/react-server/src/ReactServerFormatConfig.js': (
409 bundleType,
410 entry,
411 dependencies,
@@ -398,7 +423,7 @@ const forks = Object.freeze({
423 if (!rendererInfo.isServerSupported) {
424 return null;
425 }
401 - return `react-server/src/forks/ReactServerFormatConfig.${rendererInfo.shortName}.js`;
426 + return `./packages/react-server/src/forks/ReactServerFormatConfig.${rendererInfo.shortName}.js`;
427 }
428 }
429 throw new Error(
@@ -408,7 +433,7 @@ const forks = Object.freeze({
433 );
434 },
435
411 - 'react-server/src/ReactFlightServerConfig': (
436 + './packages/react-server/src/ReactFlightServerConfig.js': (
437 bundleType,
438 entry,
439 dependencies,
@@ -426,7 +451,7 @@ const forks = Object.freeze({
451 if (!rendererInfo.isServerSupported) {
452 return null;
453 }
429 - return `react-server/src/forks/ReactFlightServerConfig.${rendererInfo.shortName}.js`;
454 + return `./packages/react-server/src/forks/ReactFlightServerConfig.${rendererInfo.shortName}.js`;
455 }
456 }
457 throw new Error(
@@ -436,7 +461,7 @@ const forks = Object.freeze({
461 );
462 },
463
439 - 'react-client/src/ReactFlightClientHostConfig': (
464 + './packages/react-client/src/ReactFlightClientHostConfig.js': (
465 bundleType,
466 entry,
467 dependencies,
@@ -454,7 +479,7 @@ const forks = Object.freeze({
479 if (!rendererInfo.isServerSupported) {
480 return null;
481 }
457 - return `react-client/src/forks/ReactFlightClientHostConfig.${rendererInfo.shortName}.js`;
482 + return `./packages/react-client/src/forks/ReactFlightClientHostConfig.${rendererInfo.shortName}.js`;
483 }
484 }
485 throw new Error(
@@ -465,7 +490,7 @@ const forks = Object.freeze({
490 },
491
492 // We wrap top-level listeners into guards on www.
468 - 'react-dom/src/events/EventListener': (bundleType, entry) => {
493 + './packages/react-dom/src/events/EventListener.js': (bundleType, entry) => {
494 switch (bundleType) {
495 case FB_WWW_DEV:
496 case FB_WWW_PROD:
@@ -475,28 +500,34 @@ const forks = Object.freeze({
500 return null;
501 } else {
502 // Use the www fork which is integrated with TimeSlice profiling.
478 - return 'react-dom/src/events/forks/EventListener-www.js';
503 + return './packages/react-dom/src/events/forks/EventListener-www.js';
504 }
505 default:
506 return null;
507 }
508 },
509
485 - 'use-sync-external-store/src/useSyncExternalStore': (bundleType, entry) => {
510 + './packages/use-sync-external-store/src/useSyncExternalStore.js': (
511 + bundleType,
512 + entry
513 + ) => {
514 if (entry.startsWith('use-sync-external-store/shim')) {
487 - return 'use-sync-external-store/src/forks/useSyncExternalStore.forward-to-shim';
515 + return './packages/use-sync-external-store/src/forks/useSyncExternalStore.forward-to-shim.js';
516 }
517 if (entry !== 'use-sync-external-store') {
518 // Internal modules that aren't shims should use the native API from the
519 // react package.
492 - return 'use-sync-external-store/src/forks/useSyncExternalStore.forward-to-built-in';
520 + return './packages/use-sync-external-store/src/forks/useSyncExternalStore.forward-to-built-in.js';
521 }
522 return null;
523 },
524
497 - 'use-sync-external-store/src/isServerEnvironment': (bundleType, entry) => {
525 + './packages/use-sync-external-store/src/isServerEnvironment.js': (
526 + bundleType,
527 + entry
528 + ) => {
529 if (entry.endsWith('.native')) {
499 - return 'use-sync-external-store/src/forks/isServerEnvironment.native';
530 + return './packages/use-sync-external-store/src/forks/isServerEnvironment.native.js';
531 }
532 },
533 });
scripts/rollup/plugins/use-forks-plugin.js
+6 -2
@@ -30,15 +30,19 @@ let resolveCache = new Map();
30 function useForks(forks) {
31 let resolvedForks = new Map();
32 Object.keys(forks).forEach(srcModule => {
33 + // Fork paths are relative to the project root. They must include the full
34 + // path, including the extension. We intentionally don't use Node's module
35 + // resolution algorithm because 1) require.resolve doesn't work with ESM
36 + // modules, and 2) the behavior is easier to predict.
37 const targetModule = forks[srcModule];
38 resolvedForks.set(
35 - require.resolve(srcModule),
39 + path.resolve(process.cwd(), srcModule),
40 // targetModule could be a string (a file path),
41 // or an error (which we'd throw if it gets used).
42 // Don't try to "resolve" errors, but cache
43 // resolved file paths.
44 typeof targetModule === 'string'
41 - ? require.resolve(targetModule)
45 + ? path.resolve(process.cwd(), targetModule)
46 : targetModule
47 );
48 });