A new Router to guide you
Toronto 11th Nov 2019
Eduardo
San Martin Morote
🌍 Vue core team
👨‍💻 Freelance
📍Paris
    
    
    

Routing in you App
the 1st week
Routing in your App
after a year
SPA
Routers

Opinionated
Flexibility
Three kind of routers
- Imperative
 - Declarative
 - Configuration-based
 
Imperative
Page.js
âś… Programmatic navigation
❌ Declarative navigation
âś… Navigation Guards
❌ Dynamic routing (add/remove routes)
❌ Declarative routing
Dynamic routing
router.addRoute('/some-route', options)
router.removeRoute('/some-route')⚠️ not actual API
Reach Router
<Router>
  <Home path="/" />
  <UserProfileEdit path="/users/:id/edit" />
</Router><div>
  <Link to="/">Home</Link>
  <Link to={`/users/${this.user.id}/edit`} />
</div>Reach router / React Router
Declarative
âś… Programmatic navigation (w/ hooks)
âś…Â Declarative navigation
❌ Navigation Guards
âś… Dynamic routing
âś…Â Declarative routing
Â
Vue Router
const router = new Router({
  mode: 'history',
  routes: [
    { path: '/', component: Home },
    { path: '/users/:id', component: UserProfile },
  ]
})<div>
  <router-link to="/">Home</router-link>
  <router-link :to="`/users/${this.user.id}`">
    My Profile
  </router-link>
</div>Vue router
Configuration based
âś…Â Programmatic navigation
âś…Â Declarative navigation
âś… Navigation Guards
⚠️ Dynamic routing (add/remove routes)
❌ Declarative routing
đź—‚ HISTORY
🚦 ROUTER
📦 COMPONENTS
📦 COMPONENTES
<router-view/><router-link to="/">Home</router-link>🚦 ROUTER
- 
	
Route matching​
- 
		
​match()
 - 
		
​resolve()
 
 - 
		
 - 
	
Navigation
- 
		
​​currentRoute
 - 
		
push() replace(), ...
 - 
		
​beforeEach(), ...
 
 - 
		
 - 
	
Creating routes
- 
		
new Router({ routes }) - 
		
addRoutes()
 
 - 
		
 
đź—‚ HISTORy
- 
	
JS ↔ URL
- 
		
push() replace(), ...
 - 
		
listen()
 
 - 
		
 
The
Good PARTS

📦 router-view
<router-view/>- Dynamically render current view
 - Pass params as props
 
$route
📦 router-link
- Resolve target location
 - Render an anchor tag with link
 - Handles click event
 - Applies active classes
 
<router-link to="/">Home</router-link><router-link :to="{ name: 'User', params: {id: '2'}}">...</router-link>$route
$router
Normalized Route
{
  path: '/users/2',
  fullPath: '/users/2?q=foo'
  name: 'UserProfile',
  query: { q: foo },
  hash: '',
  params: { id: '2' },
  meta: {}
}Navigation
Guards

Global Guards
router.beforeEach((to, from, next) => {
  // verify roles based on `to`
  // ...
  // call `next` *once*
  if (!isLoggedIn) next('/login') // redirect to login
  else if (!isAuthorized) next(false) // abort
  else next() // allow navigation
})Per-route Guards
{
  path: '/admin',
  component: AdminPanel,
  beforeEnter (to, from, next) {
    if (isAdmin) next()
    else next(false)
  },
}in-component guards
export default {
  name: 'AdminPanel',
  data: () => ({ adminInfo: null }),
  async beforeRouteEnter (to, from, next) {
    const adminInfo = await getAdminInfo()
    next(vm => {
      vm.adminInfo = adminInfo
    })
  },
}beforeEach
beforeEnter
beforeRouteEnter
next()
next(false)
/posts ➡️ /admin
/posts
Admin.vue
beforeEnter
beforeRouteEnter
next()
/posts ➡️ /admin
Fetch Admin Component
The
Sad PARTS

No clear Division of responsibilities
History
Router

router.beforeEach
function beforeEach(guard: NavigationGuard): ListenerRemover {
  this.beforeGuards.push(guard)
  return () => {
    const i = this.beforeGuards.indexOf(guard)
    if (i > -1) this.beforeGuards.splice(i, 1)
  }
}router.push
function push (location, onComplete, onAbort) {
  this.history.push(location, onComplete, onAbort)
}No clear Division of responsibilities
- Harder to contribute
 - Harder to extend
 
beforeRouteEnter
<template>
  <p>Hello {{ user.name }}!</p>
</template>
<script>
  export default {
    data: () => ({ user: null }),
    async beforeRouteEnter(to, from, next) {
      const user = await fetchCurrentUser()
      next(vm => {
        vm.user = user
      })
    }
  }
</script>Oops!
After mounted
Differences between guards
beforeRouteEnter
beforeRouteUpdate beforeRouteLeave
❌ No access to the component instance (this)
âś… Can pass a callback
âś… Access to the component instance (this)
❌ Callback is ignored
Save
Vue
Router

đź—‚ HISTORy
- 
	
Store visited URLs
 - 
	
JS ↔ URL
- 
		
push() replace(), ...
 - 
		
listen()
 
 - 
		
 
🚦 ROUTER
- 
	
Route matching
- 
		
​match()
 - 
		
​resolve()
 
 - 
		
 - 
	
Navigation
- 
		
​​currentRoute
 - 
		
push() replace(), ...
 - 
		
​beforeEach(), ...
 
 - 
		
 - 
	
Creating routes
- 
		
new Router({ routes }) - 
		
addRoutes()
 
 - 
		
 
đź—‚ HISTORy
- 
	
push() replace()
 - 
	
listen()
 - URL parsing
 
API
- Modify the Location
 - Parses URL
	
- path
 - query
 - hash
 
 - Notifies when Location changes
 - Handles Encoding problems
 - Can be overloaded
 
Responsibilities / Expectations
🚦 ROUTER
- 
	
Route matching
- 
		
​resolve()
 
 - 
		
 - Adding Route Records
	
- 
		
addRouteRecord
 - 
		
removeRouteRecord
 
 - 
		
 
- 
	
Navigation
- 
		
​​currentRoute
 - 
		
push() replace(), ...
 
 - 
		
 - 
	
Navigation Guards
- 
		
​beforeEach(), ...
 
 - 
		
 - Dynamic Routing
	
- 
		
​addRoute / removeRoute
 
 - 
		
 
🚦 ROUTER
🛣 Matcher
🛣 Matcher
- 
	
Route matching
- 
		
​resolve()
 
 - 
		
 - Adding Route Records
	
- 
		
addRouteRecord
 - 
		
removeRouteRecord
 
 - 
		
 
API
- Resolving a Router Location to a Route Record
 - Only handles the path of URL
 - Handles priority of Route Records
 - Parses/handle params
 
Responsibilities / Expectations
- 
	
Navigation
- 
		
​​currentRoute
 - 
		
push(), replace()
 
 - 
		
 - 
	
Navigation Guards
- 
		
​beforeEach(), ...
 
 - 
		
 - Dynamic Routing
 - Lazy loading Pages
 - Error handlers
 
🚦 ROUTER
API
- Async navigation
 - Trigger Navigation guards
 - Expose current Route Location
 - Handle redirections
 - Dynamic Routing
 
Responsibilities / Expectations
Cool
new
Vue
Router

The Future is in Typescript
export type RouteRecord =
  | RouteRecordSingleView
  | RouteRecordMultipleViews
  | RouteRecordRedirect- Easier to contribute
 - Less regressions
 - Improved discoverability
 
<router-link
  to="/about"
  v-slot="{ href, route, navigate, isActive }"
>
  <NavLink
    :active="isActive"
    :href="href"
    @click="navigate"
  >{{ route.fullPath }}</NavLink>
</router-link>router-link scoped slot
Navigation Failures
- Navigating to the current location
 - Cancelling navigation in a guard
	
- Redirecting
 - Aborting
 
 - Unhandled Errors
 
try {
  await router.push('/somewhere')
} catch (err) {
  console.log(
    'Did not make it to ' + err.to.fullPath
  )
}Navigation Failures
Complete Stacktraces


Complete Stacktraces
function createHistory(): RouterHistory {
  const base = createAbstractHistory()
  const navigationStack = []
  
  // overload push/replace methods to write the stack
  function push() {}
  function replace() {}
  
  return {
    ...base,
    
    push,
    replace,
    navigationStack,
  }
}Custom History
new Router({
  mode: createHistory(),
})Custom History
new Router({
  routes: [
    { path: '/(.*)', name: 'NotFound' },
    { path: '/home', name: 'Home' }
  ]
})Path Ranking
paths.esm.dev
router.addRoute({ name: 'User', path: '/users/:id' })
router.addRoute({ name: 'UserById', path: '/users/:id(\d+)' })
router.addRoute({ name: 'Myself', path: '/users/me' })
router.removeRoute({ name: 'TemporaryRoute' })
router.resolve('/users/me') // -> { name: 'Myself' }
router.resolve('/users/230') // -> { name: 'UserById' }
router.resolve('/users/posva') // -> { name: 'User' }Dynamic Routing

secret
routes
if (loggedIn) router.addRoutes()
import { useLink } from 'vue-router'
function useConfirmLink(to, message) {
  const link = useLink(to)
  
  function navigate() {
    if (window.confirm(message)) return link.navigate()
  }
  
  return { ...link, navigate }
}Composition API
Composition API
​useLink
useLocation
onBeforeRouteLeave
onBeforeRouteUpdate
More Tests
- Full unit test coverage
 - Automated Cross Browser E2E tests
 
RFCs
- Scoped Slot API for router-link
 - Better active matching
 - a11y improvements
 - More navigation information
 
Vue 2 & 3
- Support both versions
 
Vue Router 4
Vue Router 4
Vue 2
Vue 3
Focus on supporting Vue 3
Smaller improvements for Vue 2
Sponsors 🙌
esm.dev/sponsor

Thanks! đź––
A new Router to guide you
By Eduardo San Martin Morote
A new Router to guide you
Vue official router has been a pleasure to build apps with but as the community grows, so do the router needs. However, it hasn't kept up as good as I wish it had with all the good proposals out there. As a result, we have also taken more time to work on the new version of Vue router and shaping an API that will serve Vue 2 and Vue 3. A more extensible router, easier to contribute and new architecture from scratch. Let's talk about what has changed in the new Router and all the improvements we are bringing.
- 3,813
 

