Commit Graph
317 Commits
Author SHA1 Message Date
JuanandGitHub 6af2d31476 [DevTools] Enable logger for internal build of DevTools extensions (#22476) 2021-09-30 14:13:13 -04:00
JuanandGitHub ebb7d9253d [DevTools] Extension reports logged events when feature flag is enabled (#22475) 2021-09-30 13:47:14 -04:00
Brian VaughnandGitHub b66195162c DevTools: Fixed potential cache miss when insepcting elements (#22472) 2021-09-30 12:48:53 -04:00
Brian VaughnandGitHub 8dc1d44765 Scheduling Profiler: Show Suspense resource .displayName (#22451) 2021-09-28 11:29:33 -04:00
Behnam MohammadiandGitHub 7079d1e330 prevent unused exec getCurrentValue after re-render (#22442) 2021-09-27 17:20:32 -04:00
Behnam MohammadiandGitHub 2e65621da8 Add isArray in devTools utils (#22438) 2021-09-27 17:17:30 -04:00
Andrew ClarkandGitHub bbd31d8ff1 Make root.unmount() synchronous (#22444)
* Move flushSync warning to React DOM

When you call in `flushSync` from an effect, React fires a warning. I've
moved the implementation of this warning out of the reconciler and into
React DOM.

`flushSync` is a renderer API, not an isomorphic API, because it has
behavior that was designed specifically for the constraints of React
DOM. The equivalent API in a different renderer may not be the same.
For example, React Native has a different threading model than the
browser, so it might not make sense to expose a `flushSync` API to the
JavaScript thread.

* Make root.unmount() synchronous

When you unmount a root, the internal state that React stores on the
DOM node is immediately cleared. So, we should also synchronously
delete the React tree. You should be able to create a new root using
the same container.
2021-09-27 14:04:39 -07:00
Brian VaughnandGitHub 0152c10c71 DevTools encoding supports multibyte characters (e.g. "🟩") (#22424)
Changes our text encoding approach to properly support multibyte characters following this algorithm. Based on benchmarking, this new approach is roughly equivalent in terms of performance (sometimes slightly faster, sometimes slightly slower).

I also considered using TextEncoder/TextDecoder for this, but it was much slower (~85%).
2021-09-27 13:34:39 -04:00
Justin GrantandGitHub 6114cc919f Improve DEV errors if string coercion throws (Temporal.*, Symbol, etc.) (#22064)
* Revise ESLint rules for string coercion

Currently, react uses `'' + value` to coerce mixed values to strings.
This code will throw for Temporal objects or symbols.

To make string-coercion safer and to improve user-facing error messages,
This commit adds a new ESLint rule called `safe-string-coercion`.

This rule has two modes: a production mode and a non-production mode.
* If the `isProductionUserAppCode` option is true, then `'' + value`
  coercions are allowed (because they're faster, although they may
  throw) and `String(value)` coercions are disallowed. Exception:
  when building error messages or running DEV-only code in prod
  files, `String()` should be used because it won't throw.
* If the `isProductionUserAppCode` option is false, then `'' + value`
  coercions are disallowed (because they may throw, and in non-prod
  code it's not worth the risk) and `String(value)` are allowed.

Production mode is used for all files which will be bundled with
developers' userland apps. Non-prod mode is used for all other React
code: tests, DEV blocks, devtools extension, etc.

In production mode, in addiiton to flagging `String(value)` calls,
the rule will also flag `'' + value` or `value + ''` coercions that may
throw. The rule is smart enough to silence itself in the following
"will never throw" cases:
* When the coercion is wrapped in a `typeof` test that restricts to safe
  (non-symbol, non-object) types. Example:
    if (typeof value === 'string' || typeof value === 'number') {
      thisWontReport('' + value);
    }
* When what's being coerced is a unary function result, because unary
   functions never return an object or a symbol.
* When the coerced value is a commonly-used numeric identifier:
  `i`, `idx`, or `lineNumber`.
* When the statement immeidately before the coercion is a DEV-only
  call to a function from shared/CheckStringCoercion.js. This call is a
  no-op in production, but in DEV it will show a console error
  explaining the problem, then will throw right after a long explanatory
  code comment so that debugger users will have an idea what's going on.
  The check function call must be in the following format:
    if (__DEV__) {
      checkXxxxxStringCoercion(value);
    };

Manually disabling the rule is usually not necessary because almost all
prod use of the `'' + value` pattern falls into one of the categories
above. But in the rare cases where the rule isn't smart enough to detect
safe usage (e.g. when a coercion is inside a nested ternary operator),
manually disabling the rule will be needed.

The rule should also be manually disabled in prod error handling code
where `String(value)` should be used for coercions, because it'd be
bad to throw while building an error message or stack trace!

The prod and non-prod modes have differentiated error messages to
explain how to do a proper coercion in that mode.

If a production check call is needed but is missing or incorrect
(e.g. not in a DEV block or not immediately before the coercion), then
a context-sensitive error message will be reported so that developers
can figure out what's wrong and how to fix the problem.

Because string coercions are now handled by the `safe-string-coercion`
rule, the `no-primitive-constructor` rule no longer flags `String()`
usage. It still flags `new String(value)` because that usage is almost
always a bug.

* Add DEV-only string coercion check functions

This commit adds DEV-only functions to check whether coercing
values to strings using the `'' + value` pattern will throw. If it will
throw, these functions will:
1. Display a console error with a friendly error message describing
   the problem and the developer can fix it.
2. Perform the coercion, which will throw. Right before the line where
   the throwing happens, there's a long code comment that will help
   debugger users (or others looking at the exception call stack) figure
   out what happened and how to fix the problem.

One of these check functions should be called before all string coercion
of user-provided values, except when the the coercion is guaranteed not
to throw, e.g.
* if inside a typeof check like `if (typeof value === 'string')`
* if coercing the result of a unary function like `+value` or `value++`
* if coercing a variable named in a whitelist of numeric identifiers:
  `i`, `idx`, or `lineNumber`.

The new `safe-string-coercion` internal ESLint rule enforces that
these check functions are called when they are required.

Only use these check functions in production code that will be bundled
with user apps.  For non-prod code (and for production error-handling
code), use `String(value)` instead which may be a little slower but will
never throw.

* Add failing tests for string coercion

Added failing tests to verify:
* That input, select, and textarea elements with value and defaultValue
  set to Temporal-like objects which will throw when coerced to string
  using the `'' + value` pattern.
* That text elements will throw for Temporal-like objects
* That dangerouslySetInnerHTML will *not* throw for Temporal-like
  objects because this value is not cast to a string before passing to
  the DOM.
* That keys that are Temporal-like objects will throw

All tests above validate the friendly error messages thrown.

* Use `String(value)` for coercion in non-prod files

This commit switches non-production code from `'' + value` (which
throws for Temporal objects and symbols) to instead use `String(value)`
which won't throw for these or other future plus-phobic types.

"Non-produciton code" includes anything not bundled into user apps:
* Tests and test utilities. Note that I didn't change legacy React
  test fixtures because I assumed it was good for those files to
  act just like old React, including coercion behavior.
* Build scripts
* Dev tools package - In addition to switching to `String`, I also
  removed special-case code for coercing symbols which is now
  unnecessary.

* Add DEV-only string coercion checks to prod files

This commit adds DEV-only function calls to to check if string coercion
using `'' + value` will throw, which it will if the value is a Temporal
object or a symbol because those types can't be added with `+`.

If it will throw, then in DEV these checks will show a console error
to help the user undertsand what went wrong and how to fix the
problem. After emitting the console error, the check functions will
retry the coercion which will throw with a call stack that's easy (or
at least easier!) to troubleshoot because the exception happens right
after a long comment explaining the issue. So whether the user is in
a debugger, looking at the browser console, or viewing the in-browser
DEV call stack, it should be easy to understand and fix the problem.

In most cases, the safe-string-coercion ESLint rule is smart enough to
detect when a coercion is safe. But in rare cases (e.g. when a coercion
is inside a ternary) this rule will have to be manually disabled.

This commit also switches error-handling code to use `String(value)`
for coercion, because it's bad to crash when you're trying to build
an error message or a call stack!  Because `String()` is usually
disallowed by the `safe-string-coercion` ESLint rule in production
code, the rule must be disabled when `String()` is used.
2021-09-27 10:05:07 -07:00
Behnam MohammadiandGitHub 19c43210fd add hasOwnProperty to devTools backend (#22437) 2021-09-27 08:56:56 -04:00
Brian VaughnandGitHub c9cf7d4b5f Scheduling Profiler marks should include thrown Errors (#22419) 2021-09-24 12:56:27 -04:00
Brian VaughnandGitHub 8cd5f8d9a6 DevTools: Lazily parse indexed map sections (#22415)
Indexed maps divide nested source maps into sections, annotated with a line and column offset. Since these sections are JSON and can be quickly parsed, we can easily separate them without doing the heavier base64 and VLQ decoding process. This PR updates our sourcemap parsing code to defer parsing of an indexed map section until we actually need to retrieve mappings from it.
2021-09-24 11:09:42 -04:00
Brian VaughnandGitHub 53a419268b DevTools: Hook names optimizations (#22403)
This commit dramatically improves the performance of the hook names feature by replacing the source-map-js integration with custom mapping code built on top of sourcemap-codec. Based on my own benchmarking, this makes parsing 3-4 times faster. (The bulk of these changes are in SourceMapConsumer.js.)

While implementing this code, I also uncovered a problem with the way we were caching source-map metadata that was causing us to potential parse the same source-map multiple times. (I addressed this in a separate commit for easier reviewing. The bulk of these changes are in parseSourceAndMetadata.js.)

Altogether these changes dramatically improve the performance of the hooks parsing code.

One additional thing we could look into if the source-map download still remains a large bottleneck would be to stream it and decode the mappings array while it streams in rather than in one synchronous chunk after the full source-map has been downloaded.
2021-09-22 20:17:57 -04:00
Luna RuanandGitHub 72bbc8c6c4 [Draft] don't patch console during first render (#22308)
Previously, DevTools always overrode the native console to dim or supress StrictMode double logging. It also overrode console.log (in addition to console.error and console.warn). However, this changes the location shown by the browser console, which causes a bad developer experience. There is currently a TC39 proposal that would allow us to extend console without breaking developer experience, but in the meantime this PR changes the StrictMode console override behavior so that we only patch the console during the StrictMode double render so that, during the first render, the location points to developer code rather than our DevTools console code.
2021-09-21 15:00:11 -07:00
Konstantin PopovandGitHub ac8fe668f3 Fix typo in types.js (react-devtools-shared) (#22299)
Fix typo:

becuase -> because
2021-09-20 15:09:59 -04:00
Brian VaughnandGitHub a1ba3e97a6 Enabled enableProfilerChangedHookIndices feature flag for all builds (#22365) 2021-09-20 13:10:50 -04:00
Sebastian SilbermannandGitHub 154d6230b0 devtools: Display actual ReactDOM API name in root type (#22363) 2021-09-20 11:44:21 -04:00
Brian VaughnandGitHub c76e229f21 DevTools: Fix memory leak via alternate Fiber pointer (#22346) 2021-09-17 12:53:07 -04:00
Brian VaughnandGitHub b87d923685 Clear performance marks after measuring (#22345) 2021-09-17 10:46:42 -04:00
JuanandGitHub 2cea2a653d [DevTools] Enable hook names in standalone app (#22320) 2021-09-17 10:21:54 -04:00
Brian VaughnandGitHub ffff2c4036 Updated the utfDecodeString() method to avoid call stack exceeded error (#22330) 2021-09-17 09:52:52 -04:00
JuanandGitHub 637c91068a [DevTools] Fix runtime error when inspecting an element times out (#22329) 2021-09-15 17:19:10 -04:00
JuanandGitHub b43d3a26ab [DevTools] Add initial APIs for logging instrumentation events under feature flag (#22276) 2021-09-14 11:10:24 -04:00
Brian VaughnandGitHub 835acb2238 Revert Suspense cache Thenable.catch() change (#22280)
Reverts part of #22275 (adding .catch() to Thenables in Suspense caches) in response to #22275 (comment).

After taking another look with fresh eyes, I think I see the "uncaught error" issue I initially noticed was in checkForUpdate() (which did not pass an error handler to .then)
2021-09-09 15:26:41 -04:00
Brian VaughnandGitHub 0bfcef0315 Add named hooks support to react-devtools-inline (#22263)
This commit builds on PR #22260 and makes the following changes:
* Adds a DevTools feature flag for named hooks support. (This allows us to disable it entirely for a build via feature flag.)
* Adds a new Suspense cache for dynamically imported modules. (This allows a component to suspend while importing an external code chunk– like the hook names parsing code).
* DevTools supports a hookNamesModuleLoaderFunction param to import the hook names module. I wish this could be handles as part of the react-devtools-shared package, but I'm not sure how to configure Webpack (4) to serve the chunk from react-devtools-inline. This seemed like a reasonable workaround.

The PR also contains an additional unrelated change:
* Removes pre-fetch optimization (added in DevTools: Improve named hooks network caching #22198). This optimization was mostly only important for cases where sources needed to be re-downloaded, something which we can now avoid in most cases¹ thanks to using cached responses already loaded by the page. (I tested this locally on Facebook and this change has no negative performance impact. There is still some overhead from serializing the JS through the Bridge but that's constant between the two approaches.)

¹ The case where we don't benefit from cached responses is when DevTools are opened after the page has already loaded certain scripts. This seems uncommon enough that I don't think it justified the added complexity of prefetching.
2021-09-09 15:25:26 -04:00
Brian VaughnandGitHub a4adb8b5e2 DevTools Suspense cache cleanup (#22275) 2021-09-09 09:28:17 -04:00
Brian VaughnandGitHub b37e1bd4aa Moved named hooks code (and tests) from react-devtools-extensions to react-devtools-shared (#22260) 2021-09-07 11:44:49 -04:00
Brian VaughnandGitHub b3884e22b2 DevTools: Improve named hooks network caching (#22198)
While testing the recently-launched named hooks feature, I noticed that one of the two big performance bottlenecks is fetching the source file. This was unexpected since the source file has already been loaded by the page. (After all, DevTools is inspecting a component defined in that same file.)

To address this, I made the following changes:
- [x] Keep CPU bound work (parsing source map and AST) in a worker so it doesn't block the main thread but move I/O bound code (fetching files) to the main thread.
- [x] Inject a function into the page (as part of the content script) to fetch cached files for the extension. Communicate with this function using `eval()` (to send it messages) and `chrome.runtime.sendMessage()` to return its responses to the extension).

With the above changes in place, the extension gets cached responses from a lot of sites- but not Facebook. This seems to be due to the following:
* Facebook's response headers include [`vary: 'Origin'`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary).
* The `fetch` made from the content script does not include an `Origin` request header.

To reduce the impact of cases where we can't re-use the Network cache, this PR also makes additional changes:
- [x] Use `devtools.network.onRequestFinished` to (pre)cache resources as the page loads them. This allows us to avoid requesting a resource that's already been loaded in most cases.
- [x] In case DevTools was opened _after_ some requests were made, we also now pre-fetch (and cache in memory) source files when a component is selected (if it has hooks). If the component's hooks are later evaluated, the source map will be faster to access. (Note that in many cases, this prefetch is very fast since it is returned from the disk cache.)

With the above changes, we've reduced the time spent in `loadSourceFiles` to nearly nothing.
2021-09-01 14:10:07 -04:00
Luna RuanandGitHub 95c476cb73 Add consoleManagedByDevToolsDuringStrictMode feature flag in DevTools #22215 2021-08-30 15:16:53 -07:00
Luna RuanandGitHub 13b3f255f8 [DevTools] Throw error in console without interfering with logs (#22175) 2021-08-30 14:37:49 -07:00
Luna RuanandGitHub 40d56fb64b added react native feature flags (#22199)
lunaruan commented 3 days ago • 
This PR adds separate DevTools feature flag configurations for react-devtools-core. It also breaks the builds down into facebook specific and open source flags so we can experiment in React Native.

Tested yarn build:standalone, yarn build:backend, yarn build:standalone:fb, and yarn build:backend:fb and inspected the output to make sure each package used the correct feature flags (the first two use core-oss and the latter two use fb-oss.
2021-08-30 14:12:52 -07:00
Sebastian SilbermannandGitHub 5615429662 devtools: Don't display hook index of useContext (#22200) 2021-08-30 15:44:12 -04:00
JuanandGitHub 2554f0d08f [DevTools] Add utils for perfomance marks (#22180) 2021-08-26 13:05:15 -04:00
Luna RuanandGitHub 87a1f82ef2 Console Logging for StrictMode Double Rendering (#22030)
React currently suppress console logs in StrictMode during double rendering. However, this causes a lot of confusion. This PR moves the console suppression logic from React into React Devtools. Now by default, we no longer suppress console logs. Instead, we gray out the logs in console during double render. We also add a setting in React Devtools to allow developers to hide console logs during double render if they choose.
2021-08-25 15:35:38 -07:00
Brian VaughnandGitHub 673d3256bd Added performance timings to DevTools named hooks parsing (#22173) 2021-08-25 15:39:15 -04:00
Brian VaughnandGitHub a932f1511b DevTools: Replaced WeakMap with LRU for inspected element cache (#22160)
We use an LRU for this rather than a WeakMap because of how the "no-change" optimization works.

When the frontend polls the backend for an update on the element that's currently inspected, the backend will send a "no-change" message if the element hasn't updated (rendered) since the last time it was asked. In thid case, the frontend cache should reuse the previous (cached) value. Using a WeakMap keyed on Element generally works well for this, since Elements are mutable and stable in the Store. This doens't work properly though when component filters are changed, because this will cause the Store to dump all roots and re-initialize the tree (recreating the Element objects).

So instead we key on Element ID (which is stable in this case) and use an LRU for eviction.
2021-08-23 19:22:31 -04:00
Holger BenlandGitHub 482d848170 [DevTools] Add options for disabling some features (#22136) 2021-08-20 12:55:50 -04:00
Brian VaughnandGitHub e1d53e4d33 DevTools: Reset cached indices in Store after elements reordered (#22147) 2021-08-20 12:53:28 -04:00
Sebastian SilbermannandGitHub 84f2e3a018 DevTools: update error indices when elements are added/removed (#22144) 2021-08-20 11:55:42 -04:00
Brian VaughnandGitHub b54e67dc6c Scheduling Profiler: Add network measures (#22112) 2021-08-18 12:17:59 -04:00
Brian VaughnandGitHub 80a6a5c73e Fixed Components tree indentation bug for Chrome extension (#22083)
By upgrading react-virtualized-auto-sizer to 1.0.6

See https://github.com/bvaughn/react-virtualized-auto-sizer/pull/39
2021-08-12 20:41:56 -04:00
Brian VaughnandGitHub 75998b720d Updated @reach packages to fix unmount bug (#22075) 2021-08-11 14:43:25 -04:00
Byron LukandGitHub b694529172 Devtools/function context change (#22047) 2021-08-10 14:16:54 -04:00
Brian VaughnandGitHub 104cd23817 Scheduling profiler: Added lane labels and durations to React measures (#22029) 2021-08-05 13:50:39 -04:00
Brian VaughnandGitHub abcc0fc26e DevTools scheduling profiler: Add React component measures (#22013) 2021-08-03 13:03:29 -04:00
Vyacheslav 'SLEL' SolominandGitHub 8f58479c00 [DevTools] Fix: highlight updates with memoized components (#22008) 2021-08-03 11:50:00 -04:00
Kevin ChavezandGitHub f2ec168af1 Switch on enableProfilerChangedHookIndices flag for OSS devtools builds (#22011) 2021-08-03 08:55:15 -04:00
Brian VaughnandGitHub c6ec6b99f1 DevTools: Scheduling profiler (#22006) 2021-08-02 14:30:43 -04:00
40d345be50 Devtools: Refactor imperative theme code (#21950)
Co-authored-by: Brian Vaughn <[email protected]>
2021-08-02 11:20:04 -04:00
Brian VaughnandGitHub 6c5dd58d02 Scheduling profiler UX changes (#21990) 2021-08-02 09:23:48 -04:00