javascripthttp-redirectdocumentationpython-sphinxurl-fragment

How do I maintain URL fragments when using Sphinx and Sphinx-reredirects to handle URL redirects?


I recently restructured a Sphinx documentation project by moving around a lot of files and arranging them into associated folders. This process changed the location urls of the existing documentation causing the old links to return 404s.

I used the sphinx-reredirects extension to handle redirects to the new location of the documentation pages. This works fine for most of the URLs. However, URLs that contain fragments/anchors, for example: an old URL, https://example.com/docs#example1, would redirect to https://example.com/new-location/docs, losing the #example1 in the process. These fragments are very important as a lot of links to the docs scattered accross the internet contain fragments and removing them would cause the links to lose important context.

I have tried intercepting the redirect using JavaScript, but I can't seem to capture the URL that causes the redirect in my code before it happens.

// Function to capture and log the current URL
function logOldUrl() {
  const oldUrl = window.location.href;
  const hash = window.location.hash;
  console.log("Old URL before redirect:", oldUrl, hash);
}

// Add an event listener to capture the URL before unloading the page
window.addEventListener("beforeunload", logOldUrl);

window.onload = logOldUrl;

// Optionally, listen for visibility changes to detect potential navigation changes
document.addEventListener("visibilitychange", () => {
  if (document.visibilityState === "hidden") {
    logOldUrl();
  }
});

logOldUrl();

It keeps logging the new URL. Are there any events that Sphinx-reredirects emits before a redirect happens or are there any other ways to tackle this issue?


Solution

  • In case anyone runs into this issue. A viable workaround would be writing a custom HTML redirect file for sphinx-reredirects and including a script that captures the fragment and appends it to url.

    For example:

    <!DOCTYPE html>
    <html>
      <head>
        <noscript>
          <meta http-equiv="refresh" content="0; url=${to_uri}" />
        </noscript>
        <script>
          var target = "${to_uri}";
          // If there's a URL hash, append it to the target URL
          if (window.location.hash) {
            window.location.replace(target + window.location.hash);
          } else {
            window.location.replace(target);
          }
        </script>
      </head>
    </html>
    

    Note that you have to register your custom redirect template in your conf.py.


    UPDATE: Since my PR got merged, the HTML template above is sphinx-reredirects' default HTML template. Thus, fragments are now preserved out of the box.