Just recently, I upgraded a Vue 2 application that heavily uses Vue Router and TypeScript to Vue 3. During the migration process, I switched a function from reading the route using this.$route in the Options API to using useRoute() in the Composition API. However, after making this change, the component failed to load with the following error:
[Vue warn]: injection "Symbol(route location)" not found.
at <Content pageName="homepage" onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< viewRef > >
at <RouterView>
at <Website>
To make troubleshooting easier, I have minimized the app as much as possible and here is the set up where the error occurs:
The dependencies I am working with are: "vue": "^3.3.4", "vue-router": "^4.2.1",
This is the entry point code:
website.js
import { createApp } from "vue"
import router from "./routes/router.js"
import Website from "./website.vue"
const app = createApp(Website)
app.use(router)
app.mount("#shop")
Now, let's take a look at the base component:
website.vue
<template lang="pug">
router-view
</template>
<script lang="ts">
import { defineComponent } from "vue"
export default defineComponent({
name: "Website"
})
Next, the router configuration:
router.js
import { createRouter, createWebHistory } from "vue-router"
import Content from "../components/content.vue"
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: "/",
components: {
default: Content,
},
props: {
default: { pageName: "homepage" }
},
]
})
export default router
Now, let's examine the active component that previously worked with the Options API:
content.vue
<template lang="pug">
h1 {{ myroute.fullPath }}
</template>
<script>
export default {
name: "Content",
props: {
pageName: {
type: String,
required: true
}
},
computed: {
myroute() {
return this.$route
}
}
}
</script>
When using the Composition API, the component looks like this:
content.vue
<template lang="pug">
h1 {{ myroute.fullPath }}
</template>
<script>
import { useRoute } from "vue-router"
export default {
name: "Content",
props: {
pageName: {
type: String,
required: true
}
},
setup(props) {
const route = useRoute()
return {
myroute: route
}
}
}
</script>
However, when switching to TypeScript implementation like this:
content.vue
<template lang="pug">
h1 {{ myroute.fullPath }}
</template>
<script lang="ts>
import { useRoute } from "vue-router"
import { defineComponent } from "vue"
export default defineComponent ({
name: "Content",
props: {
pageName: {
type: String,
required: true
}
},
setup(props) {
const route = useRoute()
return {
myroute: route
}
}
})
</script>
An unexpected warning pops up:
[Vue warn]: injection "Symbol(route location)" not found.
at <Content pageName="homepage" onVnodeUnmounted=fn<onVnodeUnmounted> ref=Ref< undefined > >
at <RouterView>
at <Website>
And an accompanying error message reads:
Uncaught (in promise) TypeError: can't access property "fullPath", $setup.myroute is undefined
It seems puzzling how simply transitioning to TypeScript could lead to broken functionality in the code.