Closed gureckis closed 9 months ago
This is intended are both URL are different. When using the hash history, everything used by the router goes after the hash. Note that the hash isn't sent to server requests while a real query is
@gureckis did you find any work around for that issue ? I have only one use case in my app where I don't build the URL so I endup like you.
My work around is to check if there is a token before the # and redirect the user to the correct route;
// In head of script setup in my password reset page
const queryToken = useRouteQuery<string>('token', '')
const router = useRouter()
const route = useRoute()
const currentUrl = new URL(window.location.href)
if (currentUrl.searchParams.has('token')) {
queryToken.value = currentUrl.searchParams.get('token') as string
const newUrl = router.resolve({
path: route.path,
query: { token: queryToken.value },
})
history.replaceState(
history.state,
'',
window.location.origin + window.location.pathname + newUrl.href,
)
}
Not pretty but only for password reset so won't be used a lot.
I could just use the token with currentUrl.searchParams.get('token')
but then the token persist on all page of the app so not great.
yes, i added the following to my index.html in my vue/vite project:
<body>
<div id="app"></div>
<script>
;(function () {
const location = window.location
let path = location.pathname
let searchParams = new URLSearchParams(location.search)
let hash = location.hash
// Check if there is a hash and query parameters
if (hash && location.search) {
const hashParts = hash.split('?')
const hashBase = hashParts[0]
let hashParams = new URLSearchParams(hashParts[1])
// Merge the parameters
searchParams.forEach((value, key) => {
hashParams.set(key, value)
})
// Create a new URL with merged parameters
const newHash = `${hashBase}?${hashParams.toString()}`
const newUrl = `${path}${newHash}`
// Redirect to the new URL if it's different from the current one
if (newUrl !== location.href) {
window.location.replace(newUrl)
}
}
})()
</script>
<script type="module" src="/src/core/main.js"></script>
</body>
this runs quickly before main.js loads in most cases and immediately redirects the page to a new URL with the query parameters appearing after the hash parameters. I disagree with the perspective that the vue-router team has here but this worked for my case.
Reproduction
https://codesandbox.io/p/sandbox/vue-router-test-mk5s9m?file=%2Fsrc%2Frouter.js
Steps to reproduce the bug
Access the running app here. beforeEach on each route prints to the console the value of
to.query
.When accessed this way the query parameters print out: https://mk5s9m.csb.app/#/?hi=1
when accessed this way the query parameters are empty. https://mk5s9m.csb.app/?hi=1#/
Expected behavior
The query parameters should be defined and print in both cases.
Actual behavior
The query parameters are only defined to the router when the appear after the '#' route selector
Additional information
Although it seems common to have the query parameters at the end of a URL in fact the query parameters are supposed to come before the hash tags. See section 3 of the RFC for the Uniform Resource Identifier spec: https://www.rfc-editor.org/rfc/rfc3986#section-3
I believe the solution is that the vue router needs to parse the query string even when they appear before the hash fragment.