'next.js export static - S3 - routing fails on page reload

I'm deploying a next.js app as a static export, to an s3 bucket configured for static website hosting.

I use next's build and export commands to generate the out/ directory and then copy that into my s3 bucket

The bucket then contains some files, for simplicity lets say there's just index.html and about.html

The problem is when a user hits index.html via www.website.com then navigates to www.website.com/about everything works, but reloading www.website.com/about fails of course.

www.website.com/about.html finds the correct asset to render the site however

Is there a way to export a static next.js app, host on s3, and have requests to /about proxy /about.html ?

As always, thanks for looking, and thanks even more for participating.



Solution 1:[1]

The best solution I've arrived at so far, inspired by this gist: https://gist.github.com/rbalicki2/30e8ee5fb5bc2018923a06c5ea5e3ea5

Basically when deploying the build to the s3 bucket, you can simply rename the .html files to have no .html suffix, ex: www.bucket.com/about.html -> www.bucket.com/about and now both SSR & CSR routing work as expected.

The resulting files have Content-Type: text/html despite not having the suffix, I don't know if this is problematic or not.

Solution 2:[2]

On your next.config.js file at the root of the project.

module.exports = {
    trailingSlash: true,
}

Now you can create your pages (e.g. about.jsx) inside the pages directory and Next will create a folder with the file name with an index.html file inside of it when you run the export command.

Give it a try, worked fine here.

Solution 3:[3]

RewriteRule ^([^.]+)$ $1.html [NC,L] worked fine (y)

Solution 4:[4]

Here's how Guy Hudash did it:

Assuming you already have a react.js website hosted on s3, you need to first change the S3 Routing Rules in S3 bucket -> Properties -> Static website hosting -> Redirection rules.

The new s3 console changes the routing rules format to JSON, so you’ll need to add this (don’t forget to replace myhost.com):

[
  {
    "Condition": {
      "HttpErrorCodeReturnedEquals": "404"
    },
    "Redirect": {
      "HostName": "myhost.com",
      "ReplaceKeyPrefixWith": "#!/"
    }
  },
  {
    "Condition": {
      "HttpErrorCodeReturnedEquals": "403"
    },
    "Redirect": {
      "HostName": "myhost.com",
      "ReplaceKeyPrefixWith": "#!/"
    }
  }
]

These rules add #!/ as the prefix to the URL in the case of a 403 or 404 error. This solves the react-router issue and now it will load the right page.

Now we would like to remove this prefix from the url for a cleaner solution. You’ll need to edit you _app.js and add:

import {useRouter} from 'next/router';

const MyApp = ({ Component, pageProps }) => {
  const router = useRouter();
  const path = (/#!(\/.*)$/.exec(router.asPath) || [])[1];
  if (path) {
    router.replace(path);
  }

  return (
    <Component {...pageProps} />
  );
};
export default MyApp;

You may refer to the blog-post itself... or if you are using any other routing solution than NextJS for you application, or looking for more detailed explanation then look at: Mark Biek blog

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 James
Solution 2 R. Karlus
Solution 3 letrungdo
Solution 4 RegarBoy