<HashRouter> keeps the route in the fragment: example.com/#/person/john. That single # changes everything about deployment, because a fragment is never sent to the server. The host sees a request for example.com/ and returns the one HTML file it has; the router reads window.location.hash from there. No rewrite rules at all.
Swap it in wherever the last subsection put <BrowserRouter>; it takes the same basename and children. That makes it right in a narrow set of cases: a demo on GitHub Pages 29 or in an S3 bucket, an app on a CDN you cannot configure, a page opened from the filesystem, and an Electron 20,509 shell where file:// paths make the History API awkward.
Everywhere else, prefer <BrowserRouter>. Hash URLs are worse for search engines and link previews, the fragment never reaches the server so server rendering cannot know which route to render, and its original job — jumping to an anchor — collides with the router's use of it. hashType, which chose between #/path, #path and #!/path, is gone; the format is fixed at #/path.