Vue-router: Not matching custom root without trailing slash in HTML5 mode

Created on 9 Apr 2016  路  16Comments  路  Source: vuejs/vue-router

vue: 1.0.21
vue-router: 0.7.13

I want to use the HTML5 history mode with a custom root /admin, but Vue Router seems to make a distinction between the paths /admin and /admin/: It only loads my component for / when the trailing slash is present. In the Hashbang mode everything works.

const router = new VueRouter({
  root: '/admin',
  history: true
})

router.map({
  '/': {
    component: PresenterSelection
  }
})

If I console.log(this.$route), it puts

Route {path: "", matched: null, router: Router}

I would expect it to either ignore the difference in trailing slashes, or automatically redirect. I'll be using the hashbang mode for now, but it would be great if this could be fixed.

All 16 comments

Hey, I tried to reproduce your issue but was unable to. Could your provide more details? Internally vue-router trims trailing slash on root property anyway.

I configured the router with root: '/admin', but if I visit /admin in the browser, it doesn't match any route if I use the HTML5 history. It _does_ work if I visit /admin/.

I think that the problem is here: https://github.com/vuejs/vue-router/blob/dev/src/history/html5.js#L24

Here is the code with the content of the url variable at relevant moments:

start () {
    this.listener = (e) => {
      let url = location.pathname + location.search // url === '/admin'
      if (this.root) {
        url = url.replace(this.rootRE, '') // url === '', but should be '/'
      }
      this.onChange(url, e && e.state, location.hash)
    }
    window.addEventListener('popstate', this.listener)
    this.listener()
  }

So to make sure that both urls in the browser, with or without trailing slash, work, there should be a check if url is empty.

You misunderstood root's purpose, it's for adding a prefix, e.g. for matching the production url.
Say you have a server and you deploy your index.html to foo.com, it would work just fine if you leave out the root option, but what happens when you deploy to foo.com/bar? It would mess up with vue-router's routing. So you should use bar as root in this case.

If you really want to use 'admin' as root, /admin/admin is what the url should be.
I guess what you need is a 'default' route, checkout redirect.

No, I understand this. I want to use /admin as a prefix for the routes, but when I visit /admin, I want it to match a route, but it doesn't. It matches if I visit /admin/ and it of course matches all the subroutes like /admin/profile. But, as I said, without the trailing slash, no route gets matched and no Component gets called.

As I said, if I visit /admin, and I console.log(this.$route), it outputs

Route {path: "", matched: null, router: Router}

but this can't be correct behaviour, because I defined

const router = new VueRouter({
  root: '/admin',
  history: true
})

router.map({
  '/': {
    component: PresenterSelection
  }
})

so I'd expect, if I visit /admin in the browser, to see my PresenterSelection component, but I get _nothing_, because no route gets matched. If I visit /admin/(note the trailing slash), I see the PresenterSelection component.

OK I managed to reproduce this behaviour. Interestingly it doesn't work on 0.7.13 but on 0.7.11 going to /admin displays component properly

Sorry I didn't read your issue carefully...
Maybe we need a special case for root being the route

if (this.root) {
  if (location.pathname == this.root) {
    url = url.replace(this.rootRE, '/') 
  } else {
    url = url.replace(this.rootRE, '')
  }
}

But for now, I guess you can try to define your route as ''?

router.map({
  '': {
    component: PresenterSelection
  },
  '/': {
    component: PresenterSelection
  }
})

UPDATE: I just tested, using '' as route worked.

I tested that when I first encountered the problem, and now again, and it doesn't seem to work. I still get exactly the same error. Sorry.

@danieldiekmeier Can you provide a repro on jsfiddle/codepen etc.?

@fnlctrl I tried, but you'd need a server for the HTML5 history mode to work.

I'm not sure what's the holdup here. @bartlomieju was able to reproduce it and said it worked in 0.7.11, I linked the relevant part of the code and I linked the commit where the code was changed between the versions where it worked and where it doesn't work anymore. What more is needed to get this reverted and working again?

@danieldiekmeier actually the part you linked is not that relevant. My guess the "culprit" is RouteRecognizer. I'll try to look into that later tonight.

Okay so the code which causes this situation is from route-recognizer.js:
path = tryDecode(path)
if (!path) return
In v0.7.11 the function continued and handled this URL but now /admin url is considered malformed. @yyx990803 what's your opinion on this situation?

Sorry to bring this up again, but could you release a new version to NPM, containing this fix? Would be greatly appreciated! <3

Same waiting on the fix as well, would be greatly appreciated. Or somebody tell me how to incorporatie this fix myself. Do I need to recompile the node package or something?

@stephan-v here is a quick & dirty fix I did for my app

router.beforeEach(transition => {
    if (transition.to.path == '') {
        transition.replace('/');
    } else {
        transition.next();
    }
});

has this been fixed because I am having this exact issue and it is so obnoxious\

also, the preview solution didnt work for me because i am using

router.redirect({
    '*': '/404'
});

so it immediately gets sent to 404..

Was this page helpful?
0 / 5 - 0 ratings