karol-f / vue-custom-element

Vue Custom Element - Web Components' Custom Elements for Vue.js
https://karol-f.github.io/vue-custom-element/
MIT License
1.97k stars 187 forks source link

DisconnectedCallback Performance #181

Closed shaydoc closed 4 years ago

shaydoc commented 4 years ago

Hi This is more of a question. We have a RichText Editor where we use custom elements for little Status Chips, these have nice behaviour, with popovers for settings etc.... A user added some 60 of them to a document, what we noticed when transitioning between pages, the disconnectedCallback gets fired on all of them and it can be laggy, would this be caused by the expense of destroying the Vue Instance on all 60 elements ? Basically should we look to rewrite this compoent without Vue?

karol-f commented 4 years ago

Hi, I'm sure that it can be optimized from my side a little bit. I don't promise anything but will try to look at it. Regards.

shaydoc commented 4 years ago

I just tested with the https://github.com/vuejs/vue-web-component-wrapper and it does not present the same issue perf issue 🤔

karol-f commented 4 years ago

@shaydoc Can You prepare some example so it will be easier to debug?

I have some questions:

About https://github.com/vuejs/vue-web-component-wrapper - did You manually trigger $destroy (https://github.com/vuejs/vue-web-component-wrapper#lifecycle) as this is needed actually, otherwise components will stay in memory.

shaydoc commented 4 years ago

@karol-f the components are literally a single button. I did not manually call destroy on vue-component-wrapper lifecycle like you mentioned, maybe thats why i experienced no issue.

however i do inject the vuex store into the component, in fact its potentially the vuex store teardown causing the pain now that you mention it. i must verify this with some further investigation.

shaydoc commented 4 years ago

issue lay in our own code. thanks for the tip...

karol-f commented 4 years ago

@shaydoc It's great that You've found the issue.

Can You please share what people having similar problems should look for?

shaydoc commented 4 years ago

@karol-f Sure, So we were adding some mixins and common code into our plugins, but the problem was for every instance of the custom element the following import got executed and it kept re-adding the mixins, store and router to the Component blueprint. This only needs to happen once, so memoizeing this sorted our issue.

export const registerWidget = (element, shadow = false) => {
  element.attributes = [...element.attributes, 'uuid', 'data-diffable'].sort();
  registered.push(element);

  Vue.customElement(
    element.name,
    () => import(`@/components/widgets/EditorWidgets/${element.component}/${element.component}.vue`)
      .then((Component) => memoizeComponent(element, Component)),

  );
};
const memoizeComponent = memoize((element, Component) => {
  Component.default.store = store;
  Component.default.router = router;
  Component.default.props = {
    diffable: {
      required: false,
      default: element.diffable === undefined ? false : element.diffable,
    },
    ...Component.default.props,
  };

  // copy mixins from the component
  if (Component.default.mixins && Component.default.mixins.length) {
    Component.default.mixins = [...Component.default.mixins];
  } else {
    Component.default.mixins = [];
  }

  // add default mixin for all widgets
  Component.default.mixins.push(EditorWidgetsMixin);

  // add inline widget mixin for inline widgets
  if (element.isInlineElement) {
    Component.default.mixins.push(EditorInlineWidgetsMixin);
  }

  return Component.default;
});