bvaughn / react-devtools-experimental

Experimental rewrite of the React DevTools extension
https://react-devtools-experimental.now.sh
MIT License
965 stars 55 forks source link

`Uncaught DOMException: Failed to execute 'postMessage' on 'Window': #<HTMLAllCollection> could not be cloned.` #322

Closed SimenB closed 5 years ago

SimenB commented 5 years ago

Not sure what triggers it...

Untitled 2019-06-13 17_22_20

All I'm doing is hitting the inspect button, then hovering a bunch of elements. FWIW clicking doesn't do anything except trigger the same error

This is using 9eb6d34 (6/12/2019) on Chrome 74.0.3729.169 macOS 10.14.5


Really looking forward to using this, it looks incredibly slick! Great job 😀

bvaughn commented 5 years ago

Where is this test app?

SimenB commented 5 years ago

It's not public sorry...

Putting a breakpoint where it throws

          window.postMessage({
            source: "react-devtools-bridge",
            payload: {
              event: e,
              payload: t
            }
          }, "*", n)

e is 'inspectedElement', n is undefined and t is an absolutely massive object

image

We are using emotion, maybe that's why?

SimenB commented 5 years ago

Actually, I can reproduce on Emotion's site. Might be coincidental, but just opening up https://emotion.sh and try to inspect some elements using the react dev tools triggers the same error for me

bvaughn commented 5 years ago

Yeah, looks like inspecting something on the emotion website tries to send HTMLAllCollection through postMessage which fails. Not sure how best to handle this yet, but we have enough info to repro at least. Thanks 👍

bvaughn commented 5 years ago

Maybe fixed with 5e8678a?

Can you try re-installing the version I just deployed and seeing if it fixes things for you, @SimenB?

SimenB commented 5 years ago

Yeah, that fixed it. Thanks for the amazingly quick turnaround! 😀

bvaughn commented 5 years ago

Thanks for the confirmation! 🙇

bvaughn commented 5 years ago

Possible, slightly more expensive, alternative approach (if we find more cases of things that are unsafe to clone):

const ValueToCloneableStatusMap = new WeakMap();

// Use a hidden window to try our postMessage() with,
// so we don't trigger any of the DevTools "message" subscribers.
let contentWindow = null;

function tryToCloneValue(value) {
  if (contentWindow === null) {
    const iframe = document.createElement('iframe');
    document.body.appendChild(iframe);
    contentWindow = iframe.contentWindow;
    document.body.removeChild(iframe);
  }

  try {
    contentWindow.postMessage(value, '*');
    return true;
  } catch (error) {
    return false;
  }
}

function canValueBeCloned(value) {
  if (value == null) {
    return true;
  }

  const type = typeof value;
  if (type === 'string' || type === 'number' || type === 'boolean') {
    return true;
  }

  if (!ValueToCloneableStatusMap.has(value))  {
    ValueToCloneableStatusMap.set(value, tryToCloneValue(value));
  }

  return ValueToCloneableStatusMap.get(value);
}