Aesthetic fluff image for post. Not partricularly relevant to content.
Photo by Darran Shen

historyApiFallback troubles with webpack-dev-server and React Router

If you are using React Router for your SPA (Single Page App) routing, and are running into a problem where hitting a url directly fails to load your route, there is a relatively simple solution if you are using the webpack-dev-server package for development. In your webpack config file, add the devServer root level property, set to an object with historyApiFallback: true like so:

module.exports = {
  // standard webpack stuff
  // ...

  // add the next 3 lines
  devServer: {    historyApiFallback: true,  },};

Check the docs for more info on this property here.

This has usually taken care of the problem simply enough for me, but I ran into some new problems yesterday that were not easy for me to find a fix for.

Error: resource was blocked due to MIME type

When clicking through to a route using <Link> tags, everything loads correctly. But if I refreshed the page or entered the url manually, I received a blank page and the following error.

browser console error. error text following.

The resource from “http://localhost:8080/character/main.js” was blocked due to MIME type (“text/html”) mismatch (X-Content-Type-Options: nosniff).

The issue is somewhat obvious in hindsight, as it often is, but all I needed to do was update my index.html script for my app. My webpack bundle file is named main.js, so the update looks like so:

<!-- Before -->
<script src="main.js"></script>

<!-- After (prefix with slash so it doesn't look for this asset relatively)-->
<script src="/main.js"></script>

Thanks to this Github Issue from BenFlanagan, I realized my folly. This fixes the previous issue, but I had another waiting for me.

Error: downloadable font: download failed

browser console error. error text following

downloadable font: download failed (font-family: "Rokkitt" style:normal weight:400 stretch:100 src index:2): status=2147746065 source: http://localhost:8080/character/6cff0ff498f65766b3dc53a1442a80e9.woff2

Again, we see a familiar pattern. The browser is trying to access the woff2 file relative to our url path. For this one we need the publicPath property, which lies on the output object in webpack configs. You actually don’t need an entry or output for minimal webpack configs, but now we’ll have to add that.

module.exports = {
  entry: "./src/index.tsx",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
    publicPath: "/", // required for font loading on historyApiFallback  },

  // ...

And with that, all my issues were solved. I hope this helps anyone stuck on this issue in the future. Best of fortune to you.