🚦 The official router for Vue.js.

Overview

vue-router Build Status

This is vue-router 3.0 which works only with Vue 2.0. For the 1.x router see the 1.0 branch.

Supporting Vue Router

Vue Router is part of the Vue Ecosystem and is an MIT-licensed open source project with its ongoing development made possible entirely by the support of Sponsors. If you would like to become a sponsor, please consider:

Silver Sponsors

Vue Mastery Vuetify

Bronze Sponsors

Storyblok Storyblok


Get started with the documentation, or play with the examples (see how to run them below).

Development Setup

# install deps
npm install

# build dist files
npm run build

# serve examples at localhost:8080
npm run dev

# lint & run all tests
npm test

# serve docs at localhost:8080
npm run docs

Releasing

  • yarn run release
    • Ensure tests are passing yarn run test
    • Build dist files VERSION=<the_version> yarn run build
    • Build changelog yarn run changelog
    • Commit dist files git add dist CHANGELOG.md && git commit -m "[build $VERSION]"
    • Publish a new version `npm version $VERSION --message "[release] $VERSION"
    • Push tags git push origin refs/tags/v$VERSION && git push
    • Publish to npm npm publish

Questions

For questions and support please use the Discord chat server or the official forum. The issue list of this repo is exclusively for bug reports and feature requests.

Issues

Please make sure to read the Issue Reporting Checklist before opening an issue. Issues not conforming to the guidelines may be closed immediately.

Contribution

Please make sure to read the Contributing Guide before making a pull request.

Changelog

Details changes for each release are documented in the CHANGELOG.md file.

Stay In Touch

  • For latest releases and announcements, follow on Twitter: @vuejs

License

MIT

Copyright (c) 2013-present Evan You

Special Thanks

BrowserStack Logo

Special thanks to BrowserStack for letting the maintainers use their service to debug browser specific issues.

Comments
  • Allow absolute path change without destroying rendered components (Twitter-style modals)

    Allow absolute path change without destroying rendered components (Twitter-style modals)

    Status Quo

    In vue-router, the URL is the single source of truth. That means that no matter weither the user triggers a route from an external link, by typing out the URL himself or by clicking on a <router-link> inside our app, the same route if the URL is the same, then the same routes will be matched, and the same components will be rendered - no side-effects are taken into account.

    I consider this to be a sensible, good approach. But there are situations where this behaviour is undesired:

    The problem

    If you go to Twitter's website, and open a tweet from any place (your own timeline, someone else's timeline, a list ...), three things happen:

    1. A modal with the tweet opens
    2. the URL changes to an absolute URL pointing to that tweet
    3. Something doesn't change, though: the background of the modal. Even though we started from e.g. twitter.com/linus_borg and went to twitter.com/vuejs/status/xxxxx when we opened the modal, my profile's timeline is still in the brackground.

    The user could simply copy & paste the tweets URL, post it somewhere, go back to twitter, close the modal and continue browsing my profile. Great!

    Butr currently, this is not possible with vue-router. With vue-router, we would either have to

    • render the modal as a child-route of my timeline, which means the URL would not point to the tweet really, but to /linus_borg_/status/vuejs/status/... or something.
    • render the tweet route as an absolute path, but then the background view (my profile) would be destroyed.

    Downsides

    This breaks vue-routers philsophy of the URL as the only source of truth, because opening a tweet from timeline leads to a different view than opening the tweet's URL directly.

    Proposed Solution(s)

    Here this proposal becomes thin, and I didn't add the discussion label for nothing:

    I don't really have an idea on how to approach this. I know that it's probably very hard to implement this in vue-router as it working different to the whole route-matching pattern etc, so I'm open to ideas.

    Maybe, we could at least implement a way to "pause" the router's URL change callback? So the user can "deactivate" the router momentarily, change the URL himself, show the modal, and on closing the modal, reactivate the router?

    Or maybe this could be accomplished with named router views, if we allow route that only point to a named view , so the "normal components, e.g. the profile, stay rendered, and we show the overlay in a named view? (tested this, doesn't work right now).

    Anyways, I think this wold be a great feature for many scenarios (Spotify's uses this for its ovelays showing album / playlist / artist views anywhere, for example)

    So, what do you guys think? Any opinions? Ideas for solutions?

    feature request has workaround fixed on 4.x 
    opened by LinusBorg 91
  • 关于html5-History模式在微信浏览器内的问题

    关于html5-History模式在微信浏览器内的问题

    在开发微信中使用的页面的时候,使用微信的jssdk功能,发现一点问题

    在hash模式下,wx.config()可以正常工作,但在history模式下,安卓手机中无法正常config,会提示invalid signature的错误,IOS下则是正常的,非常困扰。查了微信的文档说安卓手机可能是pushState引起的。

    @everyone give me some help...

    opened by lmnsg 76
  • [Feature] A reload method like location.reload()

    [Feature] A reload method like location.reload()

    I have a router-view that needs to be reloaded after sending some POST requests and receiving whether the operation was successful, but

    this.$route.router.go(this.$route.path)
    

    doesn't trigger a reload even if the component's route.canReuse is set to false.

    Now I can only do

    created.apply(this) // `created` is the life-cycle hook function for the component
    

    in the ajax callback to force the router-view to update itself, which is cumbersome.

    Perhaps something like $route.router.reload() would be great, as it would be the counterpart of location.reload().

    feature request 
    opened by fnlctrl 64
  • Dynamically add child routes to an existing route

    Dynamically add child routes to an existing route

    I am building a large scale application with "mini applications" hosted within the application. Each mini application is being developed by another team. I would like to dynamically add nested child routes to an existing route to allow dynamic registration of each of the mini apps.

    for example:

    const routes = [
            {path: 'a', component: ComponentA, name: 'a'},
            {path: 'b', component: ComponentB, name: 'b'},
    ];
    
    //MiniApp.js
    export default Vue.extend({
        beforeCreate () {
            this.$router.addChildRoutes(this.$router.currentRoute.path, routes);
        },
        template: `
    <div>
      <div class="page-host">
      <router-link to="{name: 'a'}">a</router-link>
      <router-link to="{name: 'b'}">b</router-link>
      <transition name="fade" mode="out-in">
        <keep-alive><router-view class="view"></router-view></keep-alive>
      </transition>
      </div>
    </div>`,
    });
    
    //The app itself
    Vue.use(Router);
    import MiniApp from "./MiniApp";
    
    const config = {
        linkActiveClass: 'active',
        scrollBehavior: () => ({x: 0, y: 0}),
        routes: [
            {path: '/mini', component: MiniApp, name: 'mini'}},
        ]
    };
    let router = new Router(config);
    const vue = new Vue({
       router,
       template: `
    <div>
      <div class="page-host">
      <router-link to="/mini">a</router-link>
      <transition name="fade" mode="out-in">
        <keep-alive><router-view class="view"></router-view></keep-alive>
      </transition>
      </div>
    </div>`,
    }).$mount('#app');
    
    feature request group[dynamic routing] fixed on 4.x 
    opened by miki2826 42
  • Allow components to define their routes in their definition file instead of having them all in one place

    Allow components to define their routes in their definition file instead of having them all in one place

    Since components are already taking care of not polluting other places, I believe it would be really nice to have components declare their own routes (subroutes actually) in their own space. This would really help for huge apps and it would favor components reusability. I was thinking of a 'routes' object in the component's definition object but this could be in a vue file as well.

    feature request needs RFC 
    opened by booss 40
  • Failed to mount component: template or render function not defined. (found in root instance)

    Failed to mount component: template or render function not defined. (found in root instance)

    I write it in this case, but it is wrong. http://router.vuejs.org/en/essentials/getting-started.html

    "vue": "^2.0.1",
    "vue-router": "^2.0.0",
    "vuex": "^2.0.0"
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
    <div id="app">
      <h1>Hello App!</h1>
      <p>
        <!-- use router-link component for navigation. -->
        <!-- specify the link by passing the `to` prop. -->
        <!-- <router-link> will be rendered as an `<a>` tag by default -->
        <router-link to="/foo">Go to Foo</router-link>
        <router-link to="/bar">Go to Bar</router-link>
      </p>
      <!-- route outlet -->
      <!-- component matched by the route will render here -->
      <router-view></router-view>
    </div>
    </body>
    </html>
    
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    // 0. If using a module system, call Vue.use(VueRouter)
    
    // 1. Define route components.
    // These can be imported from other files
    const Foo = { template: '<div>foo</div>' }
    const Bar = { template: '<div>bar</div>' }
    
    // 2. Define some routes
    // Each route should map to a component. The "component" can
    // either be an actual component constructor created via
    // Vue.extend(), or just a component options object.
    // We'll talk about nested routes later.
    const routes = [
      { path: '/foo', component: Foo },
      { path: '/bar', component: Bar }
    ]
    
    // 3. Create the router instance and pass the `routes` option
    // You can pass in additional options here, but let's
    // keep it simple for now.
    const router = new VueRouter({
      routes // short for routes: routes
    })
    
    // 4. Create and mount the root instance.
    // Make sure to inject the router with the router option to make the
    // whole app router-aware.
    const app = new Vue({
      router
    }).$mount('#app')
    
    // Now the app has started!
    
    open url http://localhost:3000/admin/#/bar
    
    opened by lzxb 39
  • No stacktrace on NavigationDuplicated error uncaught in promise

    No stacktrace on NavigationDuplicated error uncaught in promise

    Version

    3.1.1

    Reproduction link

    https://jsfiddle.net/Lom7hxn5/

    Steps to reproduce

    1. Call $router.replace or $router.push twice with same path

    What is expected?

    Error object provides stacktrace (stack property)

    What is actually happening?

    No stack trace in the error object


    When NavigationDuplicated error is thrown, there is no stack trace in the error itself so when error is reported through error reporting service like Sentry, there is absolutely no context to go with the error and so it's hard to figure out where that error originated.

    Transpiled code for the NavigationDuplicated class looks like this: https://github.com/vuejs/vue-router/blob/5141def3a21da479c2858c0d70db3cb438c3b7d0/dist/vue-router.common.js#L1935-L1946

    which is problematic because instantiating such function won't create a stacktrace. It would work fine with non-transpiled code (although I'm not suggesting to not transpile it): https://github.com/vuejs/vue-router/blob/44c63a963f05ede229d8658a45b2388e244ce00b/src/history/errors.js#L1

    One possible solution would be to manually set stack trace with:

    this.stack = (new Error()).stack;
    

    but I'm not sure how that would be done if transpilation is done by webpack/babel...

    There is also one extra bug in that code. The line that instantiates error passes a route object to the error: https://github.com/vuejs/vue-router/blob/fc42d9cf8e1d381b885c9af37003198dce6f1161/src/history/base.js#L125 but error doesn't do anything with it: https://github.com/vuejs/vue-router/blob/44c63a963f05ede229d8658a45b2388e244ce00b/src/history/errors.js#L2

    Saving route properties on the error object would also help in deciphering source of the error.

    improvement 
    opened by rchl 35
  • Allow nested routes' components to be mounted at root-level

    Allow nested routes' components to be mounted at root-level

    What problem does this feature solve?

    I'm developing a Quasar app where I have, for example, the following route structure:

    const router = new VueRouter({
      routes: [
        {
          path: '/clients',
          component: Clients,
          children: [
            {
              path: ':id',
              component: Client,
              children: [
                {
                  path: 'visits',
                  component: ClientVisits
                }
              ]
            }
          ]
        }
      ]
    })
    

    In all three routes I have a beforeRouteEnter guard that fetches data from an API and stores that data in a Vuex instance. Furthermore, ClientVisits uses the data that was fetched and stored in Client.

    In terms of UI design, though, I do not want ClientVisits to be shown as a nested child view; it needs to be at the top level. If you know Android development, ClientVisits should work as an Activity and not a Fragment.

    What does the proposed API look like?

    Perhaps if Client had no <router-view> in its template, children would then be mounted at root level?

    opened by rhyek 34
  • Cannot prevent router-link event

    Cannot prevent router-link event

    It looks like the click event on the <router-link> is handled before any custom click events:

    <router-link to="/b" @click.native.prevent="clicked">should NOT route to b</router-link>
    
    const app = new Vue({
      router,
      methods: {
      	clicked: function(e) {
            // Does not prevent route change
        	e.preventDefault()
        }
      }
      
    })
    

    See working fiddle: https://jsfiddle.net/floorish/zhyqgqpz/ The <router-link> component checks e.defaultPrevented here : https://github.com/vuejs/vue-router/blob/dev/src/components/link.js#L49 , but that is still false when it checks the condition.

    Only workaround I've found is to capture the event on a parent element (included in fiddle).

    Vue version: 2.0.7 Vue-router version: 2.0.2 Possibly related to: https://github.com/vuejs/vue-router/issues/390

    opened by floorish 34
  • Vue-Router breaks when reloading page

    Vue-Router breaks when reloading page

    Version

    2.7.0

    Reproduction link

    https://codepen.io/Juli0GT/pen/veEEpr

    Steps to reproduce

    Before reloading page thats my $route component:

    $route:Object fullPath:"/dashboard/customer-service?subnav=dashboard&activeClass=active" meta:Object (empty) name:“csDashboard" params:Object (empty) path:”/dashboard/customer-service" query:Object

    What is expected?

    Having same $route component after reload

    What is actually happening?

    If I refresh the page my router doesn’t recognise anymore my route, and my $route object looks like this:

    $route:Object fullPath:"/“ meta:Object (empty) params:Object (empty) path:”/" query:Object (empty)

    opened by Juli0GT 32
  • Feature request: enable some way of handling external links by router.

    Feature request: enable some way of handling external links by router.

    I have read a number of discussions on this and think it's worthwhile to raise this as an enhancement.

    The following esults in each element rendering as an <li> with appropriate list styling but acting like a link. The problem is that if one of the links is to an external site it fails.

    <template>
      <nav class="navs">
        <ul class="nav">
          <!-- -->
          <router-link
            class="nav__item nav__link"
            tag="li"
            active-class="-active"
            :to="nav.link"
            :key="nav.name"
            exact
            v-for="nav in navs">
            {{ nav.name }}
          </router-link>
        </ul>
      </nav>
    </template>
    

    It's possible to convolute the logic with something like the following. It requires directly inserting the <a> elements but works given minor changes to CSS or always inserting links inside <li> elements (even though if there are no external links it can be coded using <router-link tag="li" ...>).

    <ul>
      <li v-for="nav in navs">
        <a v-if="nav.external" class="nav__item nav__link" :href="nav.link">{{ nav.name }}</a>
        <router-link v-else
          class="nav__item nav__link"
          active-class="-active"
          :to="nav.link"
          :key="nav.name"
          exact
        >{{ nav.name }}</router-link>
      </li>
    </ul>
    

    I previously tried just inserting external URLs into the <router-link> elements and handling them in router.beforeEach(). It's possible to apply some heuristic checks to see if the URL is external and set window.location.href if it is. But the problem I ran into then is that using the browser back button always resulted in an error because the history is stored as localhost:8080/http:/google.com (when testing with "http://google.com" as the external link).

    It seems that that programmatically building lists of links is a common problem and that there should be a straightforward solution. Two solutions that would help me are 1) allowing the "external" prop on <router-link> elements that correctly stores history so the back button works or 2) provide some way in router.beforeEach() to prevent storing the unusable history entry. I think the first, or some variation where the externality of a link specified in the element, is the most straightforward.

    I guess another solution is a strong recommendation in documentation on how to handle this seemingly common situation.

    Thanks for considering it.

    feature request group[router-link redesign] 
    opened by bmacnaughton 32
  • Refactoring options api to use vue-router/composables break basic unit tests

    Refactoring options api to use vue-router/composables break basic unit tests

    Version

    3.6.5

    Reproduction link

    stackblitz.com

    Steps to reproduce

    1. Giving a basic options API component
      <!-- using options API -->
      <template>
         <div>{{ msg }}</div>
      </template>
      
      <script>
      export default {
        computed: {
            msg() {
               return `My route name is ${this.$route.name}`;
            }
        }
      };
      </script>
      
    2. refactoring to composition api
      <!-- Refactoring using composition-api -->
      <script>
      import { useRoute } from 'vue-router/composables';
      import { computed } from 'vue';
      
      export default {
        setup() {
          const $route = useRoute();
          const msg = computed(() => {
            `My route name is ${$route.name}`;
          });
      
          return {
            msg,
          };
        },
      };
      </script>
      
    3. The test that worked before, now breaks.
      import { mount } from '@vue/test-utils';
      import SomeComponent from './SomeComponent.vue';
      
      const $route = {
        path: '/some/path',
      };
      
      function Wrapper() {
        return mount(SomeComponent, {
          mocks: {
            $route,
          },
        });
      }
      
      test('mount component',  () => {
        const wrapper = Wrapper();
      
        expect(wrapper.exists()).toBe(true);
        // TypeError: Cannot read properties of undefined (reading 'currentRoute')
      });
      

    What is expected?

    using options/composition-api should not affect the test suite output

    What is actually happening?

    Using options/composition-api requires different ways to test (mock)


    Additional Comments

    Link to reproduction with same component written in "options API" mode https://stackblitz.com/edit/vitejs-vite-rdjvxj?file=src%2Fviews%2FAbout.test.js

    Heya! 👋 While I was waiting for the 3.6.x release, I rolled some in-house vue-router hooks as per https://github.com/vuejs/vue-router/issues/3760#issuecomment-1191774443. This allowed refactoring some options-API components to composition-api "mode" while keeping my test suite intact.

    I thought the refactor to use the official package hooks would be a simple find/replace but my test suite broke. After some digging, the reason is that the hooks implementation relies on router.currentRoute property and afterEach hook, which made the tests using the simplest $route mock as suggested in vue-test-utils docs to fail.

    Of course there's several ways to fix it: updating the test mocks as below; setting up a router with localVue as per docs; stubbing modules jest.mock(); etc;

    import { mount } from '@vue/test-utils';
    import SomeComponent from './SomeComponent.vue';
    
    const $route = {
      path: '/some/path',
    };
    
    function Wrapper() {
      return mount(SomeComponent, {
        mocks: {
    -      $route,
    +      $router: { currentRoute: $route, afterEach: vitest.fn() },
        },
      });
    }
    

    Question

    If you went this way^1, I'm sure there are good reasons for it. I'm just curious on why didn't you go with a similar approach as [email protected], as in, with a reactive object derived from getCurrentInstance().proxy.$route as per^2 which kept tests working without any change — but surely break some other stuff.


    Cheers and thanks for your work on the router! Feel free to close this if you think it's related with @vue/test-utils docs instead ✌️

    docs 
    opened by renatodeleao 1
  • backport navigation guard return values

    backport navigation guard return values

    What problem does this feature solve?

    being able to return a value in a navigaiton guard:

    router.beforeEach(to => {
      if (!user)
      return { name: 'login', query: { redirectTo: to.fullPath } }
    })
    
    ### What does the proposed API look like?
    Like v4. X
    
    <!-- generated by vue-issues. DO NOT REMOVE -->
    feature request fixed on 4.x 
    opened by 1593292349 1
  • Matcher is linear and uses too many regex

    Matcher is linear and uses too many regex

    What problem does this feature solve?

    The matcher implementation always use path-to-regex lib. It is too much for static paths, where it is possible to just compare strings.

    Also, the implementatioin is O(N), if you have 100 routes and want to match the last one (that is static), you run 100 regex tests. Regex is around ~10x slower than a simple string match and with a lookup table it is O(1).

    https://github.com/vuejs/vue-router/blob/5d7afbe25f6b212bd4adb8344da72f6227a5c6d2/src/create-matcher.js#L85-L89

    What does the proposed API look like?

    The API don't change, it is just optimization.

    I did a draft PR #3707 to show the idea.

    opened by iurisilvio 3
  • WIP: Optimized matcher

    WIP: Optimized matcher

    This is a draft implementation with some new ideas.

    • Static paths don't need regex match for most cases.
    • Match don't have to be always linear, it is possible to match only with static paths.

    Regex match is 10x slower than simple object access. I still have to run some dynamic matches to not break ordering compatibility.

    I still want to integrate it better with current code, I did this implementation to validate the issue and run some benchmarks.

    opened by iurisilvio 3
Releases(v3.6.5)
Elegant, fluent route definitions for Vue Router, inspired by Laravel. v3 is currently in beta. [email protected]

Elegant, fluent route definitions for Vue Router, inspired by Laravel. Routisan 3 is currently in beta. Stable release around the corner! npm i vue-ro

Mike Rockétt 207 Nov 4, 2022
🚦This is the repository for Vue Router 4 (for Vue 3)

vue-router This is the repository for Vue Router 4 (for Vue 3) Supporting Vue Router Vue Router is part of the Vue Ecosystem and is an MIT-licensed op

vuejs 2.6k Jan 4, 2023
Generate sitemap.xml by vue-router configuration

vue-router-sitemap Generate sitemap.xml by vue-router configuration Install npm i --save vue-router-sitemap Example usage // router.js import VueRout

Konstantin Kulinicenko 110 Nov 10, 2022
A Trie-based vue router with the ability of managing history.state.

vue-pilot A Trie-based vue router with the ability of managing history.state. Install npm install vue-pilot Features Small (8kb after gzipped). Abili

Jiang Fengming 11 Nov 16, 2020
Vue Router route config generator

vue-route-generator Vue Router route config generator. You may want to use vue-auto-routing for auto generating routing or vue-cli-plugin-auto-routing

Katashin 146 Nov 15, 2022
Hello-vue-router

hello-vue-router Project setup npm install Compiles and hot-reloads for development npm run serve Compiles and minifies for production npm run build

null 0 Dec 23, 2021
Touring Vue Router Example App

Touring Vue Router Example App This is the Vue 3 application we build step by step in the Touring Vue Router course on Vue Mastery. It's starting code

pparonson 0 Dec 30, 2021
Vue Router route config generator

vue-route-generator Vue Router route config generator. You may want to use vue-auto-routing for auto generating routing or vue-cli-plugin-auto-routing

Zen 0 Jul 3, 2021
A tool to generate routes for Vue-Router with Vite.

v-route-generate A tool to generate routes for Vue-Router with Vite. Getting Started Install v-route-generate # Choose a package manager you like. #

weiquanju 6 Dec 14, 2022
Generate Vue Router routes automatically using a markdown arborescence.

Generate Vue Router routes automatically using a markdown arborescence.

Andrea Gueugnaut 1 Aug 19, 2022
Automated generation of vue-router

自动生成router文件 通常情况下一个vue项目,随着时间的增加,router会越来越多,而大部分的代码其实都是重复的,修改很麻烦,还不如通过工具生成。

沧海 3 Oct 13, 2021
Lightweight layout resolver for Vue Router

vue-router-layout Lightweight layout resolver for Vue Router. You may want to use vue-cli-plugin-auto-routing which includes all useful features on ro

Katashin 125 Nov 27, 2022
Filesystem based route generation for Webpack + vue-router

@badrap/routdir Filesystem based route generation for Webpack + vue-router. @badrap/routdir is based on Sapper's pages and layouts features, with some

Badrap Oy 3 Jan 25, 2021
VRouteHelper - package to add that kind of syntax for vue-router.

VRouteHelper I really like how easy it is to specify routes in Laravel so I made this package to add that kind of syntax for vue-router. Any feedback

null 0 Apr 25, 2019
Generate Vue Router routing automatically for multipages

Generate Vue Router routing automatically for multipages

Macula 0 Jul 20, 2022
Vue route change loading. using Router Navigation Guards.

Vue Router Loading Easy to use and highly customizable Vue Router Loading. Getting started Install the package: npm install vue-router-loading Import

Ahmad Karimzade 16 Aug 28, 2022
A MOD version based on vue-router

vue-router-mod This is a MOD version based on vue-router 3.1.3. Introduction vue-router-mod provides extra apis to replace/remove route dynamically. I

hyjiacan 0 Dec 14, 2020
Vue Router route config generator

vue-route-generator Vue Router route config generator. You may want to use vue-auto-routing for auto generating routing or vue-cli-plugin-auto-routing

仙人掌 0 Dec 1, 2020
Generate Vue Router routing automatically

vue-auto-routing Project fork form vue-auto-routing Thanks for ktsn Generate Vue Router routing automatically. You may want to use vue-cli-plugin-auto

null 0 Jan 21, 2021