vuejs / vuepress

📝 Minimalistic Vue-powered static site generator
https://vuepress.vuejs.org
MIT License
22.58k stars 4.76k forks source link

URL fragment (hash anchor) lost when global guard fills in .html suffix #3142

Open calin-darie opened 1 year ago

calin-darie commented 1 year ago

Bug report

Steps to reproduce

  1. Create a vuepress site. This issue should be reproducible with the default theme and settings
  2. Create an .md page with heading titles. The issue is much clearer when smooth scrolling is off (so when combined with #2558 ), and with the target header is off-screen (if you need to scroll down to reach it).
  3. Instead of mypage.html#mytitle, navigate to mypage#mytitle by following external links or by pasting the URL in the browser \ Examples:

What is expected?

  1. The fragment hash is not lost
  2. The page scrolls down automatically to the desired spot.

What is actually happening?

Any URL fragment hash and query string are erased by this router guard: https://github.com/vuejs/vuepress/blob/38e98634af117f83b6a32c8ff42488d91b66f663/packages/%40vuepress/core/lib/client/redirect.js

Other relevant information

The fix is to patch the router object, instead of passing on just the path. Let me know if you'd approve a pull request:

        if (isRouteExists(router, endingHtmlUrl)) {
          next({
            ...to,
            path: endingHtmlUrl
          })
        } else if (isRouteExists(router, endingSlashUrl)) {
          next({
            ...to,
            path: endingSlashUrl
          })
        } else {
          next()
        }
      } else if (/\/$/.test(to.path)) {
        const endingHtmlUrl = to.path.replace(/\/$/, '') + '.html'
        if (isRouteExists(router, endingHtmlUrl)) {
          next({
            ...to,
            path: endingHtmlUrl
          })
calin-darie commented 1 year ago

Dirty hack. Until this gets fixed in the official version, I've patched the router global hooks:

export default ({
  Vue, // the version of Vue being used in the VuePress app
  options, // the options for the root Vue instance
  router, // the router instance for the app
  siteData // site metadata
}) => {
  // ...apply enhancements for the site.
  router.beforeHooks =[];
  router.beforeEach((to, from, next) => { // fixed version

Please let's fix vuepress v1 and let me delete this abomination.