bvaughn/react-devtools-experimental

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

SimenB opened this issue ยท 8 comments

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 ๐Ÿ˜€

Where is this test app?

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?

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

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 ๐Ÿ‘

Maybe fixed with 5e8678a?

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

Yeah, that fixed it. Thanks for the amazingly quick turnaround! ๐Ÿ˜€

Thanks for the confirmation! ๐Ÿ™‡

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);
}