@samitouri / QOS-React-2 / commits / 9eb6d3465d

Updated React version check to account for older (<15) versions

Brian Vaughn committed Jun 12, 2019 at 18:56 UTC 9eb6d3465d2c3e0afc47153890063ef5d939e75e
2 files changed +83 -2
src/backend/types.js
+3
@@ -116,6 +116,9 @@ export type ReactRenderer = {
116
117 // Only injected by React v16.8+ in order to support hooks inspection.
118 currentDispatcherRef?: {| current: null | Dispatcher |},
119 +
120 + // <= 15
121 + Mount?: any,
122 };
123
124 export type ChangeDescription = {|
src/hook.js
+80 -2
@@ -17,6 +17,7 @@ export function installHook(target: any): DevToolsHook | null {
17 function detectReactBuildType(renderer) {
18 try {
19 if (typeof renderer.version === 'string') {
20 + // React DOM Fiber (16+)
21 if (renderer.bundleType > 0) {
22 // This is not a production build.
23 // We are currently only using 0 (PROD) and 1 (DEV)
@@ -27,15 +28,92 @@ export function installHook(target: any): DevToolsHook | null {
28 // React 16 uses flat bundles. If we report the bundle as production
29 // version, it means we also minified and envified it ourselves.
30 return 'production';
30 -
31 // Note: There is still a risk that the CommonJS entry point has not
32 // been envified or uglified. In this case the user would have *both*
33 // development and production bundle, but only the prod one would run.
34 // This would be really bad. We have a separate check for this because
35 // it happens *outside* of the renderer injection. See `checkDCE` below.
36 }
37 - } catch (err) {}
37
38 + const toString = Function.prototype.toString;
39 + if (renderer.Mount && renderer.Mount._renderNewRootComponent) {
40 + // React DOM Stack
41 + const renderRootCode = toString.call(
42 + renderer.Mount._renderNewRootComponent
43 + );
44 + // Filter out bad results (if that is even possible):
45 + if (renderRootCode.indexOf('function') !== 0) {
46 + // Hope for the best if we're not sure.
47 + return 'production';
48 + }
49 + // Check for React DOM Stack < 15.1.0 in development.
50 + // If it contains "storedMeasure" call, it's wrapped in ReactPerf (DEV only).
51 + // This would be true even if it's minified, as method name still matches.
52 + if (renderRootCode.indexOf('storedMeasure') !== -1) {
53 + return 'development';
54 + }
55 + // For other versions (and configurations) it's not so easy.
56 + // Let's quickly exclude proper production builds.
57 + // If it contains a warning message, it's either a DEV build,
58 + // or an PROD build without proper dead code elimination.
59 + if (renderRootCode.indexOf('should be a pure function') !== -1) {
60 + // Now how do we tell a DEV build from a bad PROD build?
61 + // If we see NODE_ENV, we're going to assume this is a dev build
62 + // because most likely it is referring to an empty shim.
63 + if (renderRootCode.indexOf('NODE_ENV') !== -1) {
64 + return 'development';
65 + }
66 + // If we see "development", we're dealing with an envified DEV build
67 + // (such as the official React DEV UMD).
68 + if (renderRootCode.indexOf('development') !== -1) {
69 + return 'development';
70 + }
71 + // I've seen process.env.NODE_ENV !== 'production' being smartly
72 + // replaced by `true` in DEV by Webpack. I don't know how that
73 + // works but we can safely guard against it because `true` was
74 + // never used in the function source since it was written.
75 + if (renderRootCode.indexOf('true') !== -1) {
76 + return 'development';
77 + }
78 + // By now either it is a production build that has not been minified,
79 + // or (worse) this is a minified development build using non-standard
80 + // environment (e.g. "staging"). We're going to look at whether
81 + // the function argument name is mangled:
82 + if (
83 + // 0.13 to 15
84 + renderRootCode.indexOf('nextElement') !== -1 ||
85 + // 0.12
86 + renderRootCode.indexOf('nextComponent') !== -1
87 + ) {
88 + // We can't be certain whether this is a development build or not,
89 + // but it is definitely unminified.
90 + return 'unminified';
91 + } else {
92 + // This is likely a minified development build.
93 + return 'development';
94 + }
95 + }
96 + // By now we know that it's envified and dead code elimination worked,
97 + // but what if it's still not minified? (Is this even possible?)
98 + // Let's check matches for the first argument name.
99 + if (
100 + // 0.13 to 15
101 + renderRootCode.indexOf('nextElement') !== -1 ||
102 + // 0.12
103 + renderRootCode.indexOf('nextComponent') !== -1
104 + ) {
105 + return 'unminified';
106 + }
107 + // Seems like we're using the production version.
108 + // However, the branch above is Stack-only so this is 15 or earlier.
109 + return 'outdated';
110 + }
111 + } catch (err) {
112 + // Weird environments may exist.
113 + // This code needs a higher fault tolerance
114 + // because it runs even with closed DevTools.
115 + // TODO: should we catch errors in all injected code, and not just this part?
116 + }
117 return 'production';
118 }
119