Next.js: Error 404 on static export

Created on 27 Oct 2019  ·  15Comments  ·  Source: vercel/next.js

Error 404 on static export

next-learn-demo/E1-static-export/

E1-static-export

Describe the bug

Deploying on now leads to error 404 on every page request except "/". Client side navigation works fine

To Reproduce

Follow instructions here
https://nextjs.org/learn/excel/static-html-export

or:

  1. git clone https://github.com/zeit/next-learn-demo.git
  2. cd next-learn-demo
  3. cd E1-static-export
  4. npm install
  5. write next.config.js like this
const fetch = require('isomorphic-unfetch');

module.exports = {
  exportPathMap: async function() {
    const paths = {
      '/': { page: '/' },
      '/about': { page: '/about' }
    };
    const res = await fetch('https://api.tvmaze.com/search/shows?q=batman');
    const data = await res.json();
    const shows = data.map(entry => entry.show);

    shows.forEach(show => {
      paths[`/show/${show.id}`] = { page: '/show/[id]', query: { id: show.id } };
    });

    return paths;
  }
};

  1. set scripts in package. json like this:
"scripts": {
  "build": "next build",
  "export": "next export"
},
  1. npm run build
  2. npm run export
  3. cd out
  4. now

Expected behavior

static export should work fine on now platform

System information

  • OS: macOS 10.13.14
  • node v10.16.3
  • npm 6.9.0

Most helpful comment

I solved it by adding exportTrailingSlash: true, to the next.config.js file.

Exports all pages to their own files as index.html files, which worked in my case.

All 15 comments

This is caused by the necessity to publish "pages" to static accessible .html files.

When the "about" 'view' is published as a static 'page', it becomes "about.html".
If you request /about.html in the browser the page should load.

Because the dynamic router understands that "/about" means to show the about view, that works as expected. But the static system doesn't 'know' what to do for "/about", it can only respond to a request for "/about.html".

The solution I implemented was to rename all internal links, including those in exportPathMap to have an ".html" extension.

Unfortunately, this does not work for dynamic operation in development mode, or dynamic production mode. That makes for a bunch of search and replace between development and exporting a static site.

It looks to me like the real solution is for the static export system to have a way to map all internal links to expect the .html extension.

In my case, I abandoned static export. All of my "static" sites are actually published as "dynamic" apps. :-/

Awesome Next.js maintainers, I raised this question issue of confusion yesterday in spectrum (and believe the two developers above are running in to the same) https://spectrum.chat/next-js/general/static-next-pages-require-the-html-extension~05b5c3fe-b16f-47fe-86d4-7009a9b7420f

Is this the expected behavior or I can update the documentation to watch out for this gotcha?

Potentially here?
https://nextjs.org/docs#serverless-deployment

The `serverless` target will output a single lambda or [HTML file](#automatic-static-optimization) per page.
This file is completely standalone and doesn't require any dependencies to run:

- `pages/index.js` => `.next/serverless/pages/index.js`
- `pages/about.js` => `.next/serverless/pages/about.js`
- `pages/blog.js` => `.next/serverless/pages/blog.html`

The signature of the Next.js Serverless function is similar to the Node.js HTTP server callback:

I've noticed recently the nextjs team has separated church and state of nextjs and the ZEIT NOW platform, which is smart, so would be happy to put it in a now-examples if that makes sense.

Update:

When you want to use next export on ZEIT Now you can use the normal flow, but make sure to update scripts in package.json to include next export:

{
  "scripts": {
    "dev": "next",
    "build": "next build && "next export",
    "start": "next start"
  }
}


Outdated reply from earlier
So in the particular case outlined you're using next export which generates static html and can't be detected as a Next.js app by Now.

In general we recommend using the zero config approach of just running now in the project itself and it'll automatically be deployed with the right configuration including cache-control for static assets etc.

In the case outlined (next export) you'll want to add the following now.json to set up the correct headers and serving of files:

{
  "routes": [
    {
      "src": "/_next/static/(?:[^/]+/pages|chunks|runtime|css|media)/.+",
      "headers": { "cache-control": "public,max-age=31536000,immutable" },
      "continue": true
    },
    { "handle": "filesystem" },
    {"src": "/(.*)", "dest": "/$1.html"}
  ]
}

⚠ WARNING:: The above config is only useful for next export. If you're deploying without next export do not use the above configuration. Now will take care of all the configuration automatically and set up dynamic routes etc if you have them.

Closing as answered.

Note from maintainers

Updated this reply: https://github.com/zeit/next.js/issues/9213#issuecomment-548732391


Previous reply
Edit: Nevermind. While this seems to work with deployments to Now, it doesn't work with now dev.

For anyone else with multiple apps in a monorepo, I was able to use the snippet above like this:

{
  "routes": [
    { "src": "/(.*)", "dest": "app-in-subdir/$1", "continue": true },
    {
      "src": "/_next/static/(?:[^/]+/pages|chunks|runtime|css|media)/.+",
      "headers": { "cache-control": "public,max-age=31536000,immutable" },
      "continue": true
    },
    { "handle": "filesystem" },
    { "src": "/app-in-subdir/(.*)", "dest": "app-in-subdir/$1.html" }
  ]
}

The idea is to send every request to the directory with the app in it, then handle it as mentioned.

Ok everyone, I'm having this same problem. App created with nx monorepo and exported can't be deployed to any hosting platform (heroku/now).
In the case of heroku we can't build because of the 60sec timer given to build command and we're forced to deploy a static website.
Any suggestion how to solve this?

I solved it by adding exportTrailingSlash: true, to the next.config.js file.

Exports all pages to their own files as index.html files, which worked in my case.

Thanks @davidwieler, I solved this too with that solution. I forgot to update this thread.
Thanks!

@davidwieler it doesn't work with nested folders. i.e

/blog/2020/test/index.html

blog
   ├── 2020
   │   ├── test
   │   │   └── index.html

Is there any way to fix the issue that @DNature mentioned. I too get the same issue

Thank you @nicolaniro
it works fine for static export to firebase ( hosting only )

In your example file next.config.js I added one line _exportTrailingSlash: true,_ to the beginning of the module.exports

module.exports = {
exportTrailingSlash: true,
exportPathMap: async function() {
const paths = {
..................................................

and here is a working example
https://ajsbooks-nextjs-8c7d6.web.app/show/11464/

感謝 @davidwieler,
它可以在_帶有_
Firebase _的託管_ 示例下正常工作next.config.js:
module.exports = {
distDir:'../out',exportTrailingSlash
:true,
}

範例
https://ajsbooks-nextjs-8c7d6.web.app

you have two bugs here!

Bug 1 : If you connect to the website https://ajsbooks-nextjs-8c7d6.web.app/about, it will not enter the "about page"
But back to the homepage ("Index Page"),

Bug 2 :If you connect to the website https://ajsbooks-nextjs-8c7d6.web.app/noMatch404, it will not enter the "NotFound page"
But back to the homepage ("Index Page"),

I really want to know how to redirect the page to "NotFound page" correctly when page not found

I solved it by adding exportTrailingSlash: true, to the next.config.js file.

Exports all pages to their own files as index.html files, which worked in my case.

How adout "NotFound page" ?
I can't redirect the page to "NotFound page" correctly when page not found.
May you help me?

This solution is for markdown files.

Here's a link to my blogs repo where i used @saschazar/next-mdx-extended library.
https://github.com/DNature/divinehycenth.com
It's been a while since i got it to work. however, every detail you need is possibly on my repo and you can also find more options on @saschazar/next-mdx-extended`

exportTrailingSlash: true,

@ilkozlovvvcinci0 Can you present your repo please? I have the same issue, thanks!

Was this page helpful?
0 / 5 - 0 ratings