I'm trying to get a prototype Next.js project up by doing a Static html export (i.e. next export
) and then copying the generated output to AWS S3 and serving it via Cloudfront.
I've got the following two pages in the /pages
directory:
index.tsx
Pricing.tsx
Then, following along from the routing doco I added a Link
to the pricing page from the index page, like so:
<Link href="/Pricing">
<a>Pricing</a>
</Link>
This results in a link that looks like example.com/Pricing
(when you hover over it and when you click the link, the page does change to the pricing page and the browser shows example.com/Pricing
in the URL bar).
The problem is, that link is not real - it cannot be bookmarked or navigated to directly via the url bar.
The problem seems to be that when I do a next export
, Next.js generates a .html
file for each page, but the router doesn't use those .html
suffixes.
So when using the site, if the user tries to bookmark example.com/Pricing
; loading that bookmark later will fail because Cloudfront will return a 404 (because CF only knows about the .html
file).
I then tried changing my Link
to look like:
<Link href="/Pricing.html">
<a>Pricing</a>
</Link>
That causes the router to use example.com/Pricing.html
and that works fine with Cloudfront - but it actually causes a 404 during local development (i.e. using next dev
)!
Other workarounds I could try are renaming all the .html
files and removing the extension before I upload them to S3 (and make sure they get a content-type: text/html
header) - or introducing a Cloudfront lambda that does the renaming on the fly when .html
resources are requested. I don't really want to do the lambda thing, but the renaming before uploading shouldn't be too difficult.
But it feels like I'm really working uphill here. Am I doing something wrong at a basic level? How is Next.js linking supposed to work with a static html export?
Next.js version: 9.5.3-canary.23
Open the CloudFront console at https://console.aws.amazon.com/cloudfront/v3/home . Choose Create Distribution, and then choose Get Started. Under Origin Settings, for Origin Domain Name, choose the Amazon S3 bucket that you created earlier. For the other settings under Origin Settings, accept the default values.
next export builds an HTML version of your app. During next build , getStaticProps and getStaticPaths will generate an HTML file for each page in your pages directory (or more for dynamic routes). Then, next export will copy the already exported files into the correct directory.
Next. js is a server-side rendering (SSR) tool, but with version 9.3, it also supports static site generation. The idea behind it is to create server-rendered React apps that require minimal to no configuration.
An origin is the location where content is stored, and from which CloudFront gets content to serve to viewers. To specify an origin: Use S3OriginConfig to specify an Amazon S3 bucket that is not configured with static website hosting.
Alternate answer if you want your URLs to be "clean" and not have .html
on the end.
To get Next.js default URL links working properly with S3/Cloudfront, you must configure the "add a trailing slash" option in your next.config.js
:
module.exports = {
trailingSlash: true,
}
As per the documentation
export pages as index.html files and require trailing slashes, /about becomes /about/index.html and is routable via /about/. This was the default behavior prior to Next.js 9.
So now you can leave your Link
definition as:
<Link href="/Pricing">
<a>Pricing</a>
</Link>
This causes Next.js to do two things:
example.com/Pricing/
- note the /
on the endindex.html
in it's own directory - e.g. /Pricing/index.html
Many HTML servers, in their default configuration, will serve up the index.html
from inside the matching directory if they see a trailing /
character in the URL.
S3 will do this also, if you have it set up to serve as a website and IFF you access the URL through the website endpoint, as opposed to the REST endpoint.
So your Cloudfront distribution origin must be configured as a Origin type = Custom Origin
pointing at a domain something like example.com.s3-website.us-east-1.amazonaws.com
, not as an S3 Origin
.
If you have your Cloudfront/S3 mis-configured, when you hit a "trailing slash" style URL - you will probably see your browser download a file of type binary/octet-stream
containing 0 bytes
.
Edit: Beware pages with .
characters, as per issue 16617.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With