- Most RFCs have been merged.
- All merged RFCs have been implemented.
- Vue CLI now has experimental support via vue-cli-plugin-vue-next.
- Check the playground or e2e tests for a usage example.
Breaking changes compared to [email protected]
-
The
mode: 'history'
option has been replaced with a more flexible one namedhistory
:import { createRouter, createWebHistory } from 'vue-router' // there is also createWebHashHistory and createMemoryHistory createRouter({ history: createWebHistory(), routes: [], })
-
base
option is now passed as the first argument tocreateWebHistory
(and other histories) -
Catch all routes (
/*
) must now be defined using a parameter with a custom regex:/:catchAll(.*)
-
router.match
androuter.resolve
are merged together intorouter.resolve
with a slightly different signature. Check its typing through autocomplete or Router'sresolve
method -
router.getMatchedComponents
is now removed as they can be retrieved fromrouter.currentRoute.value.matched
:router.currentRoute.value.matched.flatMap(record => Object.values(record.components) )
- The
append
argument has been removed. You can manually concatenate the value to an existingpath
instead.
- The
-
RouterLink
-
If you use a
transition
, you may need to wait for the router to be ready before mounting the app:app.use(router) // Note: on Server Side, you need to manually push the initial location router.isReady().then(() => app.mount('#app'))
Otherwise there will be an initial transition as if you provided the
appear
prop totransition
because the router displays its initial location (nothing) and then displays the first location. This happens because navigations are all asynchronous now. If you have navigation guards upon the initial navigation, you might not want to block the app render until they are resolved. -
On SSR, you need to manually pass the appropriate history:
// router.js let history = isServer ? createMemoryHistory() : createWebHistory() let router = createRouter({ routes, history }) // somewhere in your server-entry.js router.push(req.url) // request url router.isReady().then(() => { // resolve the request })
-
The object returned in
scrollBehavior
is now similar toScrollToOptions
:x
is renamed toleft
andy
is renamed totop
. See RFC. -
transition
andkeep-alive
must now be used inside ofRouterView
via thev-slot
API:<router-view v-slot="{ Component }"> <transition> <keep-alive> <component :is="Component" /> </keep-alive> </transition> </router-view>
See more on the KeepAlive and the Transition examples. See RFC.
-
parent
is removed from Route locations (this.$route
and object returned byrouter.resolve
). You can still access it via thematched
array:const parent = this.$route.matched[this.$route.matched.length - 2]
-
pathToRegexpOptions
andcaseSensitive
have been replaced withsensitive
andstrict
options. They can also be directly passed when creating the router withcreateRouter()
. Any other option has been removed aspath-to-regexp
is no longer used to parse paths.
To make typings more consistent and expressive, some types have been renamed. Keep in mind these can change until stable release to ensure consistency. Some type properties might have changed as well.
vue-router@3 |
vue-router@4 |
---|---|
RouteConfig | RouteRecordRaw |
Location | RouteLocation |
Route | RouteLocationNormalized |
These are technically breaking changes but they fix an inconsistent behavior.
-
Pushing or resolving a non existent named route throws an error instead of navigating to
/
and displaying nothing. -
resolving(
router.resolve
) or pushing (router.push
) a location with missing params no longer warns and produces an invalid URL (/
), but explicitly throws an Error instead. -
Empty children
path
does not append a trailing slash (/
) anymore to make it consistent across all routes:-
By default no route has a trailing slash but also works with a trailing slash
-
Adding
strict: true
to a route record or to the router options (alongsideroutes
) will disallow an optional trailing slash -
Combining
strict: true
with a trailing slash in your routes allows you to enforce a trailing slash in your routes. In the case of nested routes, make sure to add the trailing slash to the parent and not the empty child:let routes = [ { path: '/parent/', children: [{ path: '' }, { path: 'child1/' }, { path: 'child2/' }], }, ]
-
To redirect the user to trailing slash routes (or the opposite), you can setup a
beforeEach
navigation guard that ensures the presence of a trailing slash:router.beforeEach((to, from, next) => { if (to.path.endsWith('/')) next() else next({ path: to.path + '/', query: to.query, hash: to.hash }) })
-
-
Because of the change above, relative children path
redirect
on an empty path are not supported anymore. Use named routes instead:// replace let routes = [ { path: '/parent', children: [ // this would now redirect to `/home` instead of `/parent/home` { path: '', redirect: 'home' }, { path: 'home' }, ], }, ] // with let routes = [ { path: '/parent', children: [ { path: '', redirect: { name: 'home' } }, { path: 'home', name: 'home' }, ], }, ]
Note this will work if
path
was/parent/
as the relative locationhome
to/parent/
is indeed/parent/home
but the relative location ofhome
to/parent
is/home
-
Encoding is now more consistent. The initial navigation should yield the same results are in-app navigations.
- Values in
path
,fullPath
are not decoded anymore. They will appear as provided by the browser (most browsers provide them encoded). params
,query
andhash
are now all decoded- When using
push
,resolve
andreplace
and providing astring
location or apath
property in an object, it must be encoded.params
,query
andhash
must be provided in its decoded version.
- Values in
See Contributing Guide.