Skip to content

Commit

Permalink
feat(errors): expose isRouterError
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed Jul 31, 2020
1 parent 49d3d51 commit 8d92dc0
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 54 deletions.
16 changes: 10 additions & 6 deletions docs/guide/advanced/navigation-failures.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,26 @@ When using a regular `router-link`, **none of these failures will log an error**

## Detecting Navigation Failures

_Navigation Failures_ are `Error` instances with a few extra properties. Among them, you can find a `type` property. This will allow you to check the type of the navigation failure:
_Navigation Failures_ are `Error` instances with a few extra properties. To check if an error comes from the Router, use the `isRouterError` function:

```js
import { NavigationFailureType } from 'vue-router'
import { NavigationFailureType, isRouterError } from 'vue-router'

// trying to access an admin-only route
// trying to access the admin page
router.push('/admin').catch(failure => {
if (failure) {
if (failure.type === NavigationFailureType.redirected) {
if (isRouterError(failure, NavigationFailureType.redirected)) {
// show a small notification to the user
showToast('Login in order to access the admin panel')
}
}
})
```

::: tip
If you omit the second parameter: `isRouterError(failure)`, it will only check if the error comes from the Router.
:::

## `NavigationFailureType`

`NavigationFailureType` exposes the following properties to differentiate _Navigation Failures_:
Expand All @@ -40,10 +44,10 @@ router.push('/admin').catch(failure => {
Apart from exposing a `type` property, all navigation failures expose `to` and `from` properties to reflect the current location as well as the target location for the navigation that failed:

```js
// given we are at `/`
// trying to access the admin page
router.push('/admin').catch(failure => {
if (failure) {
if (failure.type === NavigationFailureType.redirected) {
if (isRouterError(failure, NavigationFailureType.redirected)) {
failure.to.path // '/admin'
failure.from.path // '/'
}
Expand Down
3 changes: 1 addition & 2 deletions src/history/abstract.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

import type Router from '../index'
import { History } from './base'
import { isRouterError } from '../util/warn'
import { NavigationFailureType } from '../util/errors'
import { NavigationFailureType, isRouterError } from '../util/errors'

export class AbstractHistory extends History {
index: number
Expand Down
80 changes: 42 additions & 38 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,24 @@ import { AbstractHistory } from './history/abstract'

import type { Matcher } from './create-matcher'

import { isRouterError, NavigationFailureType } from './util/errors'

export default class VueRouter {
static install: () => void;
static version: string;

app: any;
apps: Array<any>;
ready: boolean;
readyCbs: Array<Function>;
options: RouterOptions;
mode: string;
history: HashHistory | HTML5History | AbstractHistory;
matcher: Matcher;
fallback: boolean;
beforeHooks: Array<?NavigationGuard>;
resolveHooks: Array<?NavigationGuard>;
afterHooks: Array<?AfterNavigationHook>;
static install: () => void
static version: string

app: any
apps: Array<any>
ready: boolean
readyCbs: Array<Function>
options: RouterOptions
mode: string
history: HashHistory | HTML5History | AbstractHistory
matcher: Matcher
fallback: boolean
beforeHooks: Array<?NavigationGuard>
resolveHooks: Array<?NavigationGuard>
afterHooks: Array<?AfterNavigationHook>

constructor (options: RouterOptions = {}) {
this.app = null
Expand All @@ -43,7 +45,8 @@ export default class VueRouter {
this.matcher = createMatcher(options.routes || [], this)

let mode = options.mode || 'hash'
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
this.fallback =
mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
Expand All @@ -69,11 +72,7 @@ export default class VueRouter {
}
}

match (
raw: RawLocation,
current?: Route,
redirectedFrom?: Location
): Route {
match (raw: RawLocation, current?: Route, redirectedFrom?: Location): Route {
return this.matcher.match(raw, current, redirectedFrom)
}

Expand All @@ -82,11 +81,12 @@ export default class VueRouter {
}

init (app: any /* Vue component instance */) {
process.env.NODE_ENV !== 'production' && assert(
install.installed,
`not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
`before creating root instance.`
)
process.env.NODE_ENV !== 'production' &&
assert(
install.installed,
`not installed. Make sure to call \`Vue.use(VueRouter)\` ` +
`before creating root instance.`
)

this.apps.push(app)

Expand Down Expand Up @@ -131,11 +131,15 @@ export default class VueRouter {
history.setupListeners()
handleInitialScroll(routeOrError)
}
history.transitionTo(history.getCurrentLocation(), setupListeners, setupListeners)
history.transitionTo(
history.getCurrentLocation(),
setupListeners,
setupListeners
)
}

history.listen(route => {
this.apps.forEach((app) => {
this.apps.forEach(app => {
app._route = route
})
})
Expand Down Expand Up @@ -204,11 +208,14 @@ export default class VueRouter {
if (!route) {
return []
}
return [].concat.apply([], route.matched.map(m => {
return Object.keys(m.components).map(key => {
return m.components[key]
return [].concat.apply(
[],
route.matched.map(m => {
return Object.keys(m.components).map(key => {
return m.components[key]
})
})
}))
)
}

resolve (
Expand All @@ -224,12 +231,7 @@ export default class VueRouter {
resolved: Route
} {
current = current || this.history.current
const location = normalizeLocation(
to,
current,
append,
this
)
const location = normalizeLocation(to, current, append, this)
const route = this.match(location, current)
const fullPath = route.redirectedFrom || route.fullPath
const base = this.history.base
Expand Down Expand Up @@ -267,6 +269,8 @@ function createHref (base: string, fullPath: string, mode) {

VueRouter.install = install
VueRouter.version = '__VERSION__'
VueRouter.isRouterError = isRouterError
VueRouter.NavigationFailureType = NavigationFailureType

if (inBrowser && window.Vue) {
window.Vue.use(VueRouter)
Expand Down
8 changes: 8 additions & 0 deletions src/util/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,11 @@ function stringifyRoute (to) {
})
return JSON.stringify(location, null, 2)
}

export function isError (err) {
return Object.prototype.toString.call(err).indexOf('Error') > -1
}

export function isRouterError (err, errorType) {
return isError(err) && err._isRouter && (errorType == null || err.type === errorType)
}
3 changes: 2 additions & 1 deletion src/util/resolve-components.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* @flow */

import { _Vue } from '../install'
import { warn, isError } from './warn'
import { warn } from './warn'
import { isError } from '../util/errors'

export function resolveAsyncComponents (matched: Array<RouteRecord>): Function {
return (to, from, next) => {
Expand Down
7 changes: 0 additions & 7 deletions src/util/warn.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,3 @@ export function warn (condition: any, message: string) {
}
}

export function isError (err: any): boolean {
return Object.prototype.toString.call(err).indexOf('Error') > -1
}

export function isRouterError (err: any, errorType: ?string): boolean {
return isError(err) && err._isRouter && (errorType == null || err.type === errorType)
}

0 comments on commit 8d92dc0

Please sign in to comment.