The Illusion of Coordinates

A study in browser history stacks, client-side routing state, and AWS CDN path resolution.

Single Page Applications (SPAs) offer a satisfyingly fluid experience by swapping out page content instantly without a full page reload. However, this fluid UI creates a conflict: the visual presentation changes, but the browser's URL address bar remains static. If a user tries to bookmark the page, refresh, or hit the browser's back button, they are either returned to the home page or ejected from the site entirely. This essay explains how we built a custom client-side router and integrated it with AWS CloudFront to support clean URLs, deep linking, and browser back/forward history navigation without code flash.

1. Intercepting Clicks and the History Stack

Our client-side router (`router.js`) intercept click events globally across the page. When a user clicks a link, the router intercepts it, checks if it points to an internal page, and prevents the default browser navigation:

document.addEventListener('click', e => {
  const link = e.target.closest('a');
  if (!link || link.getAttribute('target') === '_blank') return;
  
  const url = new URL(link.href, window.location.href);
  if (url.origin !== window.location.origin) return;
  
  e.preventDefault();
  history.pushState(null, '', url.pathname);
  loadRoute(url.pathname);
});

By using history.pushState, we push a new coordinates state onto the browser's history stack. The URL updates instantly in the address bar, but no network reload is triggered. The router then fetches the target HTML in the background, extracts the .container element, and swaps it in the DOM, fading the content in smoothly.

2. The S3 Deep Link Problem

This client-side routing works beautifully as long as the user stays on the page. But if they copy the link (e.g., /essays/LaokoonGray) and paste it into a new tab, the browser makes a literal request to AWS S3. S3 is a static file store; it looks for a physical folder or file at the path /essays/LaokoonGray. Since that path does not exist on S3 (the physical file is stored at /Essays/LaokoonGray.html), S3 returns a 404 Not Found or 403 Access Denied error.

3. CloudFront Viewer-Request Rewrites

The fastest fix is not to render another application or send every deep link through the homepage. A tiny CloudFront Function now translates public coordinates such as /essays/LaokoonGray to the physical S3 key /Essays/LaokoonGray.html during the viewer-request phase. The address bar keeps the clean URL, but CloudFront caches and returns the correct static HTML in the first response.

This preserves the static architecture while eliminating an entire HTML request from a direct deep link. It also gives crawlers the essay title, description, canonical URL, and structured data without waiting for JavaScript.

4. Client-Side Navigation After the First Page

Once any page has loaded, the lightweight router still intercepts internal links, updates browser history, fetches the next static document, and swaps its .container. Direct visits therefore receive one complete edge-cached document, while subsequent visits retain the fluid sub-50ms feel of the original SPA.

5. Real Coordinates Include Real Errors

Unknown coordinates now remain unknown: CloudFront returns a small static 404.html with an actual 404 status instead of disguising the homepage as every missing page. The original marked-index bootstrap remains as a defensive local and rollback fallback, but it is no longer part of the normal production path.