Subscribe on changes!

Beta.5 Issue when unmounting component

avatar
Jun 3rd 2021

Version

3.1.0-beta.5

Reproduction link

EDIT: https://github.com/AlexandreBonaventure/vue-beta-unmount-bug

I don't have a reproduction link because these kind of bugs are very difficult to isolate (I tried but failed to reproduce without exposing a lot of code). However, I can confirm this happened when we upgraded to beta-5 and not fixed following beta releases. I've attached a video with the devtool to provide debugging info. I'm willing to provide more information as necessary, and you guys can maybe help me figure things out as you have more insights on what's going on behind the scenes.

https://user-images.githubusercontent.com/4596409/120663906-7855ff00-c458-11eb-9972-b90f0cc818c5.mp4

Steps to reproduce

The bug happens when unmounting a component tree

What is expected?

Should work as expected

What is actually happening?

TypeError: Cannot read property 'type' of null at unmountComponent

avatar
Jun 3rd 2021
  1. Are you using Suspense?
  2. Can you confirm that: (1) it works in beta.4, and (2) still broken in beta.7?

There are only 7 commits between beta.4 and beta.5 so if possible you can build and link @vue/runtime-core locally to isolate the commit that caused the issue.

avatar
Jun 3rd 2021
  1. Not using Suspense
  2. It works in 3.x including (beta.4) and still broken in beta.7, yup!

OK doing that now!

avatar
Jun 3rd 2021

There are only 7 commits between beta.4 and beta.5 so if possible you can build and link @vue/runtime-core locally to isolate the commit that caused the issue.

So after investigation it turns out the culprit is this one commit: https://github.com/vuejs/vue-next/commit/201060717d4498b4b7933bf8a8513866ab9347e4

avatar
Jun 3rd 2021

Maybe this can help too... Here's the source code for the component which instance is null:

<script lang="ts">
import { defineComponent, h, computed, mergeProps } from 'vue';
import UIButton from './UIButton.vue';
import UIIcon from './UIIcon.vue';

export const themes = [
  'primary',
  'error',
  'warning',
];
const getProps = arr => arr.reduce((acc, theme) => ({
  ...acc,
  [theme]: {
    type: Boolean,
    required: false,
  },
}), {});

const ButtonOrSpan = (props, { attrs, slots }) => {
  if (props.interactive) {
    return h(UIButton, attrs, slots.default);
  }
  return h('span', mergeProps({ class: 'dib', style: { 'line-height': 1 } }, attrs), slots.default());
};
export default defineComponent({
  components: {
    UIIcon,
    ButtonOrSpan,
  },
  props: {
    ...getProps(themes),
    interactive: {
      type: Boolean,
      default: true,
    },
    icon: {
      type: String,
    },
  },
  emits: {
    delete: null,
  },
  setup (props) {
    const styleClasses = computed(() => {
      const filterThemes = themes.filter((theme) => props[theme]);
      if (!filterThemes.length) return ['primary'];
      return filterThemes;
    });
    const themeStyleClass = computed(() => `-${styleClasses.value.join('-')}`);
    return {
      themeStyleClass,
    };
  },
});

</script>

<template>
  <ButtonOrSpan
    unstyled
    :interactive="interactive"
    class="ui-pill"
    :class="[ $style[themeStyleClass], themeStyleClass, $style.pill ]"
  >
    <span class="dib">
      <UIIcon
        v-if="icon"
        :name="icon"
        class="icon dib v-mid mr1"
      />
      <slot />
    </span>
    <UIIcon
      v-if="interactive"
      name="x"
      class="icon dib v-mid ml1"
      @click="$emit('delete')"
    />
  </ButtonOrSpan>
</template>
avatar
Jun 3rd 2021

I'll need a bit more context on how this component is used when it throws the error - i.e. the parent chain and how this component is consumed by its parent.

Still, it's going to be very difficult to identify the issue without actual runnable reproduction so I would still strongly encourage you to try to provide one (a big one is fine). If you worry about exposing code, you can use a private repo and invite me.

avatar
Jun 4th 2021

@yyx990803 phewww, this was not an easy task but I've managed to create a minimal repro! https://github.com/AlexandreBonaventure/vue-beta-unmount-bug after yarn && yarn dev Click on the Toggle button. Screen Shot 2021-06-04 at 3 50 36 PM

The code is super contrived because I spend an hour trimming my app to get to the root of it. So now that all the code is trimmed it does not makes much sense anymore but I hope this will help you out