formkit / drag-and-drop

https://drag-and-drop.formkit.com
MIT License
1.37k stars 24 forks source link

My biggest bughunt ever. Sentry Replay + Drag an Drop FormKit = Freeze, Overheating iPhone with solution #94

Open agotfredsen82 opened 1 month ago

agotfredsen82 commented 1 month ago

A few months back We wanted to add Sentry Replay to our Nuxt3, Vue3 solution. It all seemed to work fine on desktop at first but after trying it out on iPhone we noticed that the iPhone would freeze or overheat as soon as any drag and drop happened in the where we used the form kit drag and drop .. and I mean freeze . The iPhone would need to reboot

so this was the start for a long long bug hunt , we tried everything you can imagine spend weekends. Then a few weeks back we had a break true . In The Sentry Replay platform we noticed a message saying . Mutation OVERLOAD 4450 mutations detected .

ok so now we had something to go on . but what was causing the mutation overload . we went true everything from the core of vue to the core of nuxt and true the core of FormKit Drag and Drop . Granted this much or less made us learn everything about how the reactive ways of vue but still we could not nail down what would cause it . At first it was suspected that the drag itself caused overload in reactive updates but that was not the case .

Finally by accident when we were experimenting with a Vue Teleport as a possible solution and noticed that the cloned drag object was HUGE . All classes had been flatten into style attributes and that included the children of the cloned drag object aswell .

so instead of having a small cloned drag object, known as the touchedNode .. it was huge, so tailwind 3 classes had been flatten aswell into the style object making a monster div with monster children.

so weeks of work. freezeed iPhone and overheated iPhones was simply caused by one line

copyNodeStyle(eventData.targetData.node.el, touchState.touchedNode);

This thing flatten all classes into style including the children . making a monster mutation in vue bringing the iPhone and Sentry Replay to stop working .

Fix for now is to create a plugin for FormKit Drag and Drop

const fixSentry = (parent) => {
  const parentData = parents.get(parent);

  if (!parentData) return;

  return {
    setup() {
      parentData.config.handleTouchstart = (eventData) => {
        const touchState = initTouch(eventData);
        touchState.touchedNodeDisplay = touchState.touchedNode.style.display;

        const rect = eventData.targetData.node.el.getBoundingClientRect();

        touchState.touchedNode.style.cssText = `
            width: ${rect.width}px;
            position: fixed;
            pointer-events: none;
            top: -9999px;
            z-index: 999999;
            display: none;
          `;

        document.body.append(touchState.touchedNode);

        //copyNodeStyle(eventData.targetData.node.el, touchState.touchedNode);

        touchState.touchedNode.style.display = "none";

      };
    },
  };
};

and then add it to  plugins: [animations(), fixSentry],

of course this is just a fix and copyNodeStyle is muted here just to point out that is should go .. for now but real solution would be to remove copyNodeStyle(eventData.targetData.node.el, touchState.touchedNode); so we dont get flatten drag clone monster and mutation overload in vue3 that overheats / crash the iPhone when used with Sentry Replay .

sashamilenkovic commented 3 weeks ago

@agotfredsen82 Hey there! So sorry you ran into that issue. The purpose of copyNodeStyle is to deeply copy the computed styles of it (the dragged element), as well as the computed styles of all its descendants. This may not always be necessary, so perhaps we can have that behavior be a product of an opt-in via. the config.