vuepress icon indicating copy to clipboard operation
vuepress copied to clipboard

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

Open calin-darie opened this issue 1 year ago • 1 comments

  • [x] I confirm that this is an issue rather than a question.

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:
  • without smooth scrolling, you can see the page losing the hash + no navigation happening https://docs.laravel-excel.com/3.1/getting-started/contributing#how-to-report-a-bug
  • with smooth scrolling, you get smooth scrolled to your title but the fragment anchor is lost https://vuepress.vuejs.org/miscellaneous/local-development#vuepress-sandbox-setup

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
          })
  • Output of npx vuepress info in my VuePress project: As mentioned above, it reproduces with the official vuepress docs, so this is not particularly relevant.

calin-darie avatar May 21 '23 11:05 calin-darie

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.

calin-darie avatar May 21 '23 11:05 calin-darie