vuejs / router

🚦 The official router for Vue.js
https://router.vuejs.org/
MIT License
3.74k stars 1.15k forks source link

createMemoryHistory and createWebHistory differs with base #2211

Closed yooouuri closed 2 months ago

yooouuri commented 2 months ago

Reproduction

https://github.com/yooouuri/vue-router-problem

Steps to reproduce the bug

The createCurrentLocation in createWebHistory https://github.com/vuejs/router/blob/main/packages/router/src/history/html5.ts#L38-L56 creates the current location from window.location.

Without a base set, https://localhost:5173/be/marktplaats will result in be/marktplaats. With /be/ as base, the result is /marktplaats.

(I removed the ts stuff)

function stripBase(pathname, base) {
  // no base or base is not found at the beginning
  if (!base || !pathname.toLowerCase().startsWith(base.toLowerCase()))
    return pathname
  return pathname.slice(base.length) || '/'
}

function createCurrentLocation(base, location) {
  const { pathname, search, hash } = location
  // allows hash bases like #, /#, #/, #!, #!/, /#!/, or even /folder#end
  const hashPos = base.indexOf('#')
  if (hashPos > -1) {
    let slicePos = hash.includes(base.slice(hashPos))
      ? base.slice(hashPos).length
      : 1
    let pathFromHash = hash.slice(slicePos)
    // prepend the starting slash to hash so the url starts with /#
    if (pathFromHash[0] !== '/') pathFromHash = '/' + pathFromHash
    return stripBase(pathFromHash, '')
  }

  const path = stripBase(pathname, base)

  return path + search + hash
}
image image

When I create a router with createMemoryHistory('/be/' (in SSR), and I do a router push with the URL and wait for it:

await router.push('/be/marktplaats')
await router.isReady()

The result from router.currentRoute.value is (SSR):

{
  fullPath: '/be/marktplaats',
  path: '/be/marktplaats',
  query: {},
  hash: '',
  name: 'not-found___nl',
  params: { pathMatch: [ 'be', 'marktplaats' ] },
  matched: [
    {
      path: '/:pathMatch(.*)*',
      redirect: undefined,
      name: 'not-found___nl',
      meta: {},
      aliasOf: undefined,
      beforeEnter: undefined,
      props: [Object],
      children: [],
      instances: {},
      leaveGuards: Set(0) {},
      updateGuards: Set(0) {},
      enterCallbacks: {},
      components: [Object]
    }
  ],
  meta: {},
  redirectedFrom: undefined,
  href: '/be/be/marktplaats'
}

Expected behavior

The view is matched both SSR and client side.

Actual behavior

The result in SSR and client side for router.currentRoute.value is different with same base path in createMemoryHistory and createWebHistory

The route is not matched in SSR, but in client side it is.

Additional information

No response

posva commented 2 months ago

When defining a base, it's not passed to any of the router.push() functions. I think you can check the Nuxt code base if you want to see how the implement the router, it should be helpful to you