When the application is converted into static files, the dynamic routes fail to function properly

I have a website that is statically exported but has dynamic routes.

During development, the site works fine. However, when I build and export it, then serve the static files using serve, an issue arises.

If you go to the site root and click on a link that takes you to a dynamic post page like http://localhost:3000/post/1, it will work initially. But if you refresh the page or visit directly, it returns a 404 error.

https://i.stack.imgur.com/MqQAE.gif

Why does this happen? Do dynamic routes that rely on the router query object not function properly when statically exported?

The documentation for dynamic routes doesn't mention any constraints related to using dynamic routes with static export.

The code:

Starting with the static example in Next.js, I made modifications to its pages/post/[id].tsx file by eliminating the getStaticPaths and getStaticProps (since I don't require static generation at build time) and introduced client-side fetching upon component mounting. The value of router.query.id is obtained to fetch data:

⚡ View CodeSandbox snippet here (works fine as it's in dev mode, not served from exported files)

import Head from 'next/head'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { GetPost } from '../../lib/postdata_api'
import { PostData } from '../../types/postdata'

const Post = () => {
  const [postData, setPostData] = useState<null | PostData>(null)
  const router = useRouter()
  const id = router.query.id as string
  const fetchData = async () => setPostData(await GetPost(id))

  useEffect(() => {
    if (!router.isReady) return
    fetchData()
  }, [router, router.isReady])

  if (!postData) return 'Loading...'

  return (
    <main>
      <Head>
        <title>{postData.title}</title>
      </Head>

      <h1>{postData.title}</h1>

      <p>{postData.body}</p>

      <Link href="/">
        <a>Go back to home</a>
      </Link>
    </main>
  )
}

export default Post

Expected Behaviour

I anticipated it would behave the same way as in development mode, allowing users to:

  • Click on a link on the homepage
  • Access the dynamic post page e.g., /post/1
  • Refresh or directly visit the post without encountering a 404 error

To Reproduce

  • Download the CodeSandbox project or access the GitHub repository
  • Run
    npm run export && serve out
  • Visit http://localhost:3000
  • Click on a link to view a post
  • Press refresh to see the 404 error

Answer №1

Summary

To address the issue, include the following configuration in your next.config.js file and re-export:

// next.config.js
module.exports = {
    trailingSlash: true,
}

Description

If you manually convert all exported routes to folders and rename each *.html file to index.html, you can correct this behavior. For example:

Exported route from next export:

/posts/1.html

Updated route:

/posts/1/index.html

When a page is refreshed with the URL /posts/1, adding a trailing slash will allow the HTTP request to locate the index.html file under any directory by default, displaying the static page correctly.

This was the default behavior before Next.js v9 for exports, and it can be restored by adding the specified configuration to next.config.js:

// next.config.js
module.exports = {
    trailingSlash: true,
}

I only discovered this solution recently when I encountered the same issue myself.

Source: official documentation

Answer №2

It appears that you are using the 'serve' feature from Vercel. In order to have clean URLs, it is necessary to configure a rewrite for the server.

You can refer to the guidelines provided at this link for detailed steps. By adding the following configuration to your code, you will be able to achieve pretty URLs:

// public/serve.json
{
  "rewrites": [
    { "source": "/post/*", "destination": "/post/[id].html" }
  ]
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps for storing div content (image) on server

Currently in the process of developing a web application that allows users to crop images. The goal is for users to have the ability to email the URL so others can view the cropped image, ensuring that the URL remains active indefinitely by storing every c ...

Tips for eliminating stuttering when fixing the position of an element with JavaScript

I am currently facing an issue with a webpage I created where the text freezes when scrolled down to the last paragraph, while the images continue to scroll. Although my implementation is functional, there is noticeable jankiness when using the mouse wheel ...

enable jQuery timer to persist even after page refresh

code: <div class="readTiming"> <time>00:00:00</time><br/> </div> <input type="hidden" name="readTime" id="readTime"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script&g ...

How should we provide the search query and options when using fuse.js in an Angular application?

Having previously utilized fuse.js in a JavaScript project, I am now navigating the world of Angular. Despite installing the necessary module for fuse.js, I'm encountering difficulties implementing its search functionality within an Angular environmen ...

Having difficulty toggling a <div> element with jQuery

I am attempting to implement a button that toggles the visibility of a div containing replies to comments. My goal is to have the ability to hide and display the replies by clicking the button. The "show all replies" button should only appear if there are ...

Do we still require the material-ui custom touch event? It seems to cause many issues

It has come to my attention that material-ui still relies on a package that appears to be incompatible with new React updates from Facebook. There seems to be some frustration over this issue, making it challenging to keep up with React advancements. Is th ...

Ensuring HTML integrity: <body> in Nextjs

I keep getting this warning every time I create a new Next.js app. Can someone please assist me with this issue? https://i.stack.imgur.com/cpmNQ.png Any help would be greatly appreciated. ...

I desire to share the JSON information and receive the corresponding response data

<!DOCTYPE html> <html lang="en" dir="ltr"> <head> <meta charset="utf-8"> <title></title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> </head> ...

Tips for ensuring text remains within a div container and wraps to the next line when reaching the edge

Currently, I am working on a flash card application using Angular. Users can input text in a text box, and the text will be displayed on a flash card below it. However, I have encountered an issue where if the user types a lot of text, it overflows and mov ...

In JavaScript, the clearTimeout function may not always return a

Could someone please help me troubleshoot the issue in my code snippet below? I am trying to declare a public variable and assign it to a setTimeout function. If the variable is not null, I want to clear the timeout before setting it again. However, when ...

Display a particular div when a specific image is present within another div

I'm currently working on a task, but I'm having trouble with it. If I have an image called smiley.png within a div with the class "selected." <div class="selected" style=""><img width="25" height="24" src="images/smileys/smiley.png ...

Using the Mongoose $or operator with a nested array in query conditions

Here are the schemas I am using: //ProjectModel const ProjectSchema: Schema = new Schema( owner: { type: Schema.Types.ObjectId, ref: "User" }, users: [{type: Schema.Types.ObjectId, ref: "ProjectUser", unique: true }] ); //Project Use ...

HTML5 for advanced positioning and layering of multiple canvases

I have 2 canvas layers stacked atop each other, but I need to position them relative to the entire page. The dimensions of both layers are fixed at a width of 800 and a height of 300. My goal is to center the canvas layers regardless of screen size, with ...

Discovering similarities among array elements by looping through an array

Two sets of arrays have values obtained using the data-attribute(data-product-name). One set contains the full list of available items, while the other set consists of selected items associated with a country. <!-- the item list --> <div ...

Changing the text during a reset process

I've been grappling with this issue, but it seems to slip through my fingers every time. I can't quite put my finger on what's missing. My project involves clicking an image to trigger a translate effect and display a text description. The ...

Maximizing Server Performance with Query Data Caching

I am currently developing an Express app that involves transferring data from views to a database. However, the majority of the data needs to be linked to other data within different tables in the database. For instance, there is a "choose student name" d ...

What are the ways in which Angular can offer assistance to Internet Explorer 9?

The news is out - the Angular team has just announced their support for Internet Explorer 9! This revelation has left me wondering, how is it even possible? Currently, I am an avid user of AngularJS and have dedicated time to studying its ins and outs. Fr ...

Node JS: Despite modifying the URL, the response remains unchanged

My attempt to log in to teeSpring.com and retrieve a response from another URL using a login cookie seems to be causing an issue. Upon logging into teeSpring.com, the dashboard details are returned. However, when I try to make a GET request to the second U ...

Is there a way to turn off step navigation in bootstrap?

Displayed below is a visual representation of the bootstrap step navigation component. Presently, there is an unseen 'next' button located at the bottom of the page. When this 'next' button is pressed, it transitions from 'step-1 ...

Send the user back to the previous page once authentication is complete

I am integrating Google authentication through Passport in my web application and I am facing an issue with redirecting the user back to the original page they requested after a successful sign-in. It seems like the use of location.reload() might be causin ...