Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vue router crashes when top level route target is wrapped in transition but has no child routes yet #2121

Closed
robert-wloch-iits opened this issue Jan 29, 2024 · 11 comments
Labels
external This depends on an external dependency but is kept opened to track it

Comments

@robert-wloch-iits
Copy link

robert-wloch-iits commented Jan 29, 2024

Reproduction

For reproduction please see the provided Stackblitz project

Steps to reproduce the bug

Here's a stackblitz project reproducing the issue: Vue + Vue Router Error Reproduction

Howto see the reproduction

First four steps show that transitions are working for Route A and Route B, even when going to Route C.

  1. Navigate to "Works A"
  2. Navigate to "Works B"
  3. Navigate to "Works A"
  4. Navigate to "Crashes C"
  5. Navigate to "Works A" and see the the router views are not rendered anymore.

Expected behavior

Vue router should silently ignore when there are no children defined in the router config yet (iterative approach of software development). Even if it doesn't ignore them, navigation away to a previously working route should be possible without having to reload the application in the browser tab.

Actual behavior

The top level router view in App.vue is wrapped in a Transition and for all top level router targets view components are there.
Three top level targets defined in their template a child <ViewRouter></ViewRouter> but the third, "Crashes C" has no children defined yet. When navigating to that top level target "Crashes C" and then to some other route, view router crashes.

Side-effect: When staying in Route "Crashes C" reloading the browser tab to restart the app will let a user stick in that route since navigating away from it will crash the vue router again.

Additional information

Edit on 2024-02-01:
I've updated the StackBlitz to contain the Routes "Works D", "Crashes E" and "Works F" with the examples codes from my comments below.
Specifically "Crashes E" and "Works F" are a real mystery since the only difference is the missing commented out RouterView in the template section in "Works F".

Edit on 2024-02-02:
With @K332's answer below I gave the final section in the official documentation a try, which adds :key="route.path" to the inner component tag. Doing that, I now get to see the error in the browser console when navigating away from a "Crashes" route:

[Vue warn]: Unhandled error during execution of scheduler flush. This is likely a Vue internals bug. Please open an issue at https://github.com/vuejs/core . 
  at <BaseTransition mode="out-in" appear=true persisted=false  ... > 
  at <Transition name="fade" mode="out-in" appear="" > 
  at <RouterView class="content" > 
  at <App>
chunk-ESTIRR4N.js?v=f0cae026:9623 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'parentNode')
    at parentNode (chunk-ESTIRR4N.js?v=f0cae026:9623:30)
    at ReactiveEffect.componentUpdateFn [as fn] (chunk-ESTIRR4N.js?v=f0cae026:7531:11)
    at ReactiveEffect.run (chunk-ESTIRR4N.js?v=f0cae026:429:19)
    at instance.update (chunk-ESTIRR4N.js?v=f0cae026:7571:17)
    at leavingHooks.afterLeave (chunk-ESTIRR4N.js?v=f0cae026:3679:24)
    at performRemove (chunk-ESTIRR4N.js?v=f0cae026:8018:20)
    at remove2 (chunk-ESTIRR4N.js?v=f0cae026:8030:7)
    at unmount (chunk-ESTIRR4N.js?v=f0cae026:7985:9)
    at unmountComponent (chunk-ESTIRR4N.js?v=f0cae026:8053:7)
    at unmount (chunk-ESTIRR4N.js?v=f0cae026:7954:7)

No response

Copy link
Member

posva commented Jan 29, 2024

It looks like a dup of one of the transition issues in Vue core. Maybe vuejs/core#3950. Feel free to investigate further.

@robert-wloch-iits
Copy link
Author

I've found that it is even caused by commented out RouterView code.
When you replace the contents of RouteCView.vue in the StackBlitz project by the following:

<script setup lang="ts">
</script>

<template>
<div>Ranking View</div>
</template>

then navigation between all routes is working fine.

But when you use that code, even though it does exactly the same as above, router navigation is broken as well:

<script setup lang="ts">
//import { RouterView } from 'vue-router'
</script>

<template>
  <div>Ranking View</div>
  <!--<RouterView></RouterView>-->
</template>

@robert-wloch-iits
Copy link
Author

It looks like a dup of one of the transition issues in Vue core. Maybe vuejs/core#3950. Feel free to investigate further.

I don't see how this is related. I'm not using keep-alive here in my example. With my previous comment one can suspect, that there's a deeper issue than vue-router, though.

@yueyunkeji
Copy link

vant4源代码中移动端路由如果是树形的貌似不被支持

@robert-wloch-iits
Copy link
Author

vant4源代码中移动端路由如果是树形的貌似不被支持

According to deepl your comment translates to:

Mobile routing in the vant4 source code does not seem to be supported if it is tree-based

I don't understand the relation to my post. What do you mean by "Mobile routing"? I have a client-side SPA. The problem described happens in the local desktop browser, not on a mobile device.

@robert-wloch-iits
Copy link
Author

Also, given my comment with the examples above, consider the last example vs this one:

<script setup lang="ts">
//import { RouterView } from 'vue-router'
</script>

<template>
  <div>Ranking View</div>
</template>

When you remove the commented out <!--<RouterView></RouterView>--> line in the template code, the component and router will behave correctly and work as expected.

My guess is, that the commented out code is not treated as commented out. That might be a totally separate issue with the vue template compiler, but I'm not sure about that. Any thoughts on that @posva?

@K332
Copy link

K332 commented Feb 2, 2024

well, there are two ways to solve it

1:
image

2:
image

@robert-wloch-iits
Copy link
Author

robert-wloch-iits commented Feb 2, 2024

According to the official documentation 2. doesn't resemble the examples.

✅ Confirmed that 1. solves the issue and is closest to the official documentation.
But it needs to use $route as it cannot use the destructured slot prop route. That's not clean code. Why would one then destructure route from slot props to use it in the Transition as shown in the documentation? If that :key is required on the RouterView and it can only be used with $route then the documenation should not destructure route for the transition but use $route there as well. Or, probably better for Composition API, do a const route = useRoute() in the script section first.

import { RouterView, useRoute } from 'vue-router'
const route = useRoute()
...
<RouterView v-slot="{ Component }" class="content" :key="route.fullPath">
  <Transition :name="(route?.meta?.transition as string) || 'fade'" mode="out-in" appear>
    <component :is="Component" />
  </Transition>
</RouterView>

With 1. solving the issue, the official documentation is wrong and that issue here should be used to update that documentation please.

robert-wloch-iits added a commit to robert-wloch-iits/router that referenced this issue Feb 2, 2024
The documentation update avoids situations described in vuejs#2121 and provides a link to a working demonstration project at Stackblitz.
@robert-wloch-iits
Copy link
Author

PR for updated documentation: #2126

@skirtles-code
Copy link
Contributor

I believe it's this: vuejs/core#6080.

The <!--<RouterView></RouterView>--> comment in route E is slightly misleading. It would fail for any comment, it doesn't have to be that specific comment.

With route C you end up in effectively the same scenario, because <RouterView> renders a comment node if it can't render anything else.

@posva
Copy link
Member

posva commented Mar 20, 2024

Indeed, wrapping the <router-view> from view C with a div or other HTML element and removing (instead of commenting) in view e makes everything work. Thanks a lot @skirtles-code !

@posva posva closed this as not planned Won't fix, can't repro, duplicate, stale Mar 20, 2024
@posva posva added the external This depends on an external dependency but is kept opened to track it label Mar 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external This depends on an external dependency but is kept opened to track it
Projects
None yet
Development

No branches or pull requests

5 participants