From: Eduardo San Martin Morote Date: Thu, 3 Sep 2020 16:11:28 +0000 (+0200) Subject: docs: migration guide [skip ci] X-Git-Tag: v4.0.0-beta.10~67 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8c6f3a7982c97b98911725f1a2c9cd7233751e71;p=thirdparty%2Fvuejs%2Frouter.git docs: migration guide [skip ci] --- diff --git a/docs/guide/migration/index.md b/docs/guide/migration/index.md index ca0ee39f..e84111b0 100644 --- a/docs/guide/migration/index.md +++ b/docs/guide/migration/index.md @@ -12,7 +12,7 @@ Some of new features to keep an eye on in Vue Router 4 include: - Composition API - Custom History implementation -## Breaking +## Breaking Changes ### Improvements @@ -45,9 +45,9 @@ router.resolve({ name: 'users' }) **Reason**: Same as above. -### Empty `path` in children no longer produces a trailing slash +### Named children routes with an empty `path` no longer appends a slash -Given any nested routes with an empty `path`: +Given any nested named route with an empty `path`: ```js const routes = [ @@ -62,8 +62,218 @@ const routes = [ ] ``` -Navigating to the named route `dashboard` will now produce a URL **without a trailing slash**. +Navigating or resolving to the named route `dashboard` will now produce a URL **without a trailing slash**: -Both `/dashboard` and `/dashboard/` will access the named route _dashboard_ and not _dashboard-parent_ +```js +router.resolve({ name: 'dashboard' }).href // '/dashboard' +``` + +This has an important side effect about children `redirect` records like these: + +```js +const routes = [ + { + path: '/parent', + children: [ + // this would now redirect to `/home` instead of `/parent/home` + { path: '', redirect: 'home' }, + { path: 'home' }, + ], + }, +] +``` + +Note this will work if `path` was `/parent/` as the relative location `home` to `/parent/` is indeed `/parent/home` but the relative location of `home` to `/parent` is `/home`. Learn more about relative links [in the cookbook](/cookbook/relative-links.md). + +**Reason**: This is to make trailing slash behavior consistent: by default all routes allow a trailing slash. [It can be disabled](/cookbook/trailing-slashes.md). + +### `$route` properties Encoding + +Decoded values are now consistent no matter where the navigation is initiated (older browsers will still produce unencoded `path` and `fullPath`). The initial navigation should yield the same results as in-app navigations. + +Given any [normalized route location](#TODO): + +- Values in `path`, `fullPath` are not decoded anymore. They will appear as provided by the browser (modern browsers provide them encoded). e.g. directly writing on the address bar `https://example.com/hello world` will yield the encoded version: `https://example.com/hello%20world` and both `path` and `fullPath` will be `/hello%20world`. +- `hash` is now decoded, that way it can be copied over: `router.push({ hash: $route.hash })`. +- When using `push`, `resolve` and `replace` and providing a `string` location or a `path` property in an object, **it must be encoded**. On the other hand, `params`, `query` and `hash` must be provided in its unencoded version. + +**Reason**: This allows to easily copy existing properties of a location when calling `router.push()` and `router.resolve()`. Learn more about encoding [in the cookbook](/cookbook/encoding.md). + +### Changed API + +### New `history` option to replace `mode` + +The `mode: 'history'` option has been replaced with a more flexible one named `history`: + +```js +import { createRouter, createWebHistory } from 'vue-router' +// there is also createWebHashHistory and createMemoryHistory + +createRouter({ + history: createWebHistory(), + routes: [], +}) +``` + +On SSR, you need to manually pass the appropriate history: + +```js +// 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 +}) +``` + +**Reason**: enable tree shaking of non used histories as well as implementing custom histories for advanced use cases like native solutions. + +### Moved the `base` option + +The `base` option is now passed as the first argument to `createWebHistory` (and other histories): + +```js +import { createRouter, createWebHistory } from 'vue-router' +createRouter({ + history: createWebHistory('/base-directory/'), + routes: [], +}) +``` + +### Removed `*` (star or catch all) routes + +Catch all routes (`*`, `/*`) must now be defined using a parameter with a custom regex: + +```js +const routes = [ + // pathMatch is the name of the param, e.g., going to /not/found yields + // { params: { pathMatch: ['not', 'found'] }} + { path: '/:pathMatch(.*)*', name: 'not-found' }, + // if you omit the last `*`, the `/` character in params will be encoded when resolving or pushing + { path: '/:pathMatch(.*)', name: 'bad-not-found' }, +] +// bad example: +router.resolve({ + name: 'bad-not-found', + params: { pathMatch: 'not/found' }, +}).href // '/not%2Ffound' +// good example: +router.resolve({ + name: 'not-found', + params: { pathMatch: ['not', 'found'] }, +}).href // '/not/found' +``` + +**Reason**: Vue Router doesn't use `path-to-regexp` anymore, instead it implements its own parsing system that allows route ranking and enables dynamic routing. + +### Removal of `router.match` and changes to `router.resolve` + +Both `router.match`, and `router.resolve` have been merged together into `router.resolve` with a slightly different signature. [Refer to the API](#TODO) for more details. + +**Reason**: Uniting multiple methods that were use for the same purpose. + +### Removal of `router.getMatchedComponents()` + +The method `router.getMatchedComponents` is now removed as matched components can be retrieved from `router.currentRoute.value.matched`: + +```js +router.currentRoute.value.matched.flatMap(record => + Object.values(record.components) +) +``` + +**Reason**: This method was only used during SSR and is a one liner that can be done by the user. + +### Removal of `append` prop in `` + +The `append` prop has been removed from ``. You can manually concatenate the value to an existing `path` instead: + +```html +replace +to relative child +with +to relative child +``` + +**Reason**: `append` wasn't used very often and is easy to replicate in user land. + +### Removal of `event` and `tag` props in `` + +Both `event`, and `tag` props have been removed from ``. You can use the [`v-slot` API](#TODO) to fully customize ``: + +```html +replace +About Us +with + + About Us + +``` + +**Reason**: These props were often used together to use something different from an `` tag but were introduced before the `v-slot` API and are not used enough to justify adding to the bundle size for everybody. + +### Removal of the `exact` prop in `` + +The `exact` prop has been removed because the caveat it was fixing is no longer present. See the [RFC about active matching](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0028-router-active-link.md) changes for more details. + +### **All** navigations are now always asynchronous + +All navigations, including the first one, are now asynchronous, meaning that, if you use a `transition`, you may need to wait for the router to be _ready_ before mounting the app: + +```js +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 to `transition` because the router displays its initial location (nothing) and then displays the first location. + +Note that **if you have navigation guards upon the initial navigation**, you might not want to block the app render until they are resolved unless you are doing Server Side Rendering. + +### `scrollBehavior` changes + +The object returned in `scrollBehavior` is now similar to [`ScrollToOptions`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions): `x` is renamed to `left` and `y` is renamed to `top`. See [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0035-router-scroll-position.md). + +**Reason**: making the object similar to `ScrollToOptions` to make it feel more familiar with native JS APIs and potentially enable future new options. + +### ``, ``, and `` + +`transition` and `keep-alive` must now be used **inside** of `RouterView` via the `v-slot` API: + +```vue + + + + + + + +``` + +**Reason**: This is was a necessary change. See the [related RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0034-router-view-keep-alive-transitions.md). + +### Removal of `parent` from route locations + +The `parent` property has been removed from normalized route locations (`this.$route` and object returned by `router.resolve`). You can still access it via the `matched` array: + +```js +const parent = this.$route.matched[this.$route.matched.length - 2] +``` + +**Reason**: Having `parent` and `children` creates unnecessary circular references while the properties could be retrieved already through `matched`. + +### Removal of `pathToRegexpOptions` + +The `pathToRegexpOptions` and `caseSensitive` properties of route records have been replaced with `sensitive` and `strict` options for `createRouter()`. They can now also be directly passed when creating the router with `createRouter()`. Any other option specific to `path-to-regexp` has been removed as `path-to-regexp` is no longer used to parse paths. + +### TypeScript + +To make typings more consistent and expressive, some types have been renamed. -**Reason**: This is to make things consistent +| `vue-router@3` | `vue-router@4` | +| -------------- | ----------------------- | +| RouteConfig | RouteRecordRaw | +| Location | RouteLocation | +| Route | RouteLocationNormalized |