Subscribe on changes!

Components with same filename (but different directory) are mistaken for each other and cause infinite rendering loop

avatar
Dec 15th 2020

Version

3.0.4

Reproduction link

https://github.com/jakesgordon/vue-infinite-loop-bug

Steps to reproduce

  • Create an empty vue project
  • From your App component include a custom component from ./outer/Foo.vue
  • From your outer component include an inner component from ./inner/Foo.vue
  • Expected: The App is rendered with the outer component containing the inner component
  • Actual: The outer component is rendered in an infinite loop and a "Maximum call stack size exceeded" error occurs.

What is expected?

It should render the outer component that contains the inner component and we should see...

OUTER COMPONENT
INNER COMPONENT

What is actually happening?

It renders the OUTER COMPONENT repeatedly in an infinite loop and raises a "Maximum call stack size exceeded" error


This only seems to happen if (a) the filenames are the same (in this case both Foo.vue) AND (b) the outer component imports the inner component using the same name (in this case Foo). If the filenames vary in any way this bug is not reproducible, or if the outer component imports the inner component with a different name (Bar) then this bug is not reproducible.

I ran into this bug in the context of having an outer component (imported from './page/Login.vue') that represented my entire login page but included an inner component (imported from './component/Login.vue') that contained a re-usable email/password form that I used in multiple places. I had to rip out 99% of my code to reduce it down to this simple use case.

I'm 99% sure this was working for me for a couple of weeks and something happened today that broke but I'm unable to identify exactly what changed.

Of course there is a simple workaround for me to be more explicit in my naming and actually call them LoginPage vs LoginForm

FYI: I'm on Ubuntu Linux and testing in both Chrome and Firefox latest. I hit this in a project using Snowpack, but this repro case was developed using a simple Vite project.

avatar
Dec 15th 2020

Don't need to have the same filename, just make sure that the parent and child components keep the same component name.

https://codesandbox.io/s/vue3-issue2821-q0o03

avatar
Dec 15th 2020

You need to name them differently. Using a component in its own template allows for recursive components

avatar
Dec 15th 2020

Strange timing, but I bumped into a very similar issue yesterday, and have spent the past day trying to reduce my code down to isolate the issue.

The main difference with my issue is that I'm nameing the component differently in the two different components, which I thought would get around the recursion issue. And the other difference being that this is only happening in some built versions not all, and not at all locally.

I had a setup like this (simplified example):

// src/components/Modal.vue
<template>
   <div>
     <slot></slot>
   </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "Modal",
});
</script>
// src/views/Home/Modal.vue
<template>
  <Modal>
    <p>Hello this is the home modal</p>
  </Modal>
</template>

<script lang="ts">
import { defineComponent } from "vue";

import Modal from "@/components/Modal.vue";

export default defineComponent({
  name: "HomeModal",
  components: {
    Modal,
  },
});
</script>

Despite the name property on the component being different and them being in different directories, the fact the name of the file for both is Modal.vue caused the error RangeError: Maximum call stack size exceeded.

This error only occurred when the files were built, not when serving for localhost. Strangely, it didn't always occur in built versions. When I was building with docker locally the issue didn't come up, but it did when building the docker image on Jenkins. This leads me to think that maybe it's due to a recent node version change. We use node:lts-alpine in the image, and so it may well be using different versions of node on my local machine vs Jenkins. The fact that this issue was created 12 hours ago and I discovered the problem yesterday, makes me think the bug has been recently introduced and is probably related to that.

note: I'm using vue version 3.0.3.

avatar
Dec 16th 2020

@fredrivett It's relate to version of @vue/compiler-sfc. Using a component in its own template allows for recursive components after this commit 67d1aac6ae683a3a7291dff15071d1eeacb7d22a. I think it works fine in v3.0.3. if use "@vue/compiler-sfc": "3.0.4" will be encountered this problem.

avatar
Dec 16th 2020

Maybe we need to talk about how to adjust recursively self-reference mechanism to avoid misunderstanding, i would like to create a new issue for it.