router
router copied to clipboard
slashes should not be encoded for catch all regexes
Version
4.1.6
Reproduction link
Steps to reproduce
- Load the codesandbox.io project using the link provided.
- Click on About page.
- Click on the "Add hash" button, this will call
router.replace({ hash: '#something' })
. - Notice that vue-router correctly appends the # in the url.
(https://domain.com/about.html#yippy)
. - Click on Deep About page.
- Click on the "Add hash" button.
- Notice that the url becomes
https://domain.com/test%2Fdeep%2Fabout.html#yaya
.
What is expected?
Url to become https://domain.com/test/deep/about.html#yaya
What is actually happening?
Url became https://domain.com/test%2Fdeep%2Fabout.html#yaya
This is for the front-end of a CMS-supported project, where the front part of the URL is controlled by the CMS and it varies depending on the environment. Hence the need to first match it using :pathMatch()
then match the actual page to render using :pageName()
.
Also, all pages has to be suffixed with .html, hence I am using a (kind of) complex regex to match the page. It works, however, I stumble upon this issue.
This behavior is intended for regular params like :param
because the /
is a delimiter of params, but it should probably not happen for star params (:param(.*)
)
Note to myself in edit comment
Hey, thanks for the reply. Hopefully one day I can contribute a bug fix PR myself. For now, is there any workaround that you can suggest while I wait for the official fix?
Hi, is there any update to this? Perhaps point me to the correct place where this bug occurs so I can attempt to tackle the issue?
Here's a workaround that we/I've come up with - it's not perfect as it's applied to the whole path, so we enable it only for routes with meta.patchCleanPath === true
but it works well enough for us for now (although we obviously would like to see an upstream fix, so we can get rid of this):
import { RouteLocation, RouteLocationNormalizedLoaded, RouteLocationRaw, Router } from 'vue-router'
export const patchRouter = (router: Router) => {
const cleanPath = (route) =>
[
['%2F', '/'],
['//', '/']
].reduce((path, rule) => path.replaceAll(rule[0], rule[1]), route || '')
const bindResolve = router.resolve.bind(router)
router.resolve = (
raw: RouteLocationRaw,
currentLocation?: RouteLocationNormalizedLoaded
): RouteLocation & {
href: string
} => {
const resolved = bindResolve(raw, currentLocation)
if (resolved.meta?.patchCleanPath !== true) {
return resolved
}
return {
...resolved,
href: cleanPath(resolved.href),
path: cleanPath(resolved.path),
fullPath: cleanPath(resolved.fullPath)
}
}
const routerMethodFactory = (method) => (to) => {
const resolved = router.resolve(to)
if (resolved.meta?.patchCleanPath !== true) {
return method(to)
}
return method({
path: cleanPath(resolved.fullPath),
query: resolved.query
})
}
router.push = routerMethodFactory(router.push.bind(router))
router.replace = routerMethodFactory(router.replace.bind(router))
return router
}
Hey, thanks for your patch. Will try it out. It is very appreciated.
If you find any edge cases that don't work, I'm happy to hear.
Your patch works. Good enough for us to ship the site for now. Thank you so much @dschmidt.
@posva Is there any plans to fix this behavior? I think that bef97d607d2edd77e2af8028938dc9a47bdf25fe is what caused the regression, since I used to be able to do things like redirecting to error pages without mangling the URL.