Mengatasi URL Static Export Next.js yang 404 Saat Refresh

4 menit baca.
Tags: Next.js

Static export Next.js kamu jalan normal kalau diklik-klik, tapi membuka /about langsung atau refresh halaman malah 404. Penyebabnya ada di struktur file yang ditulis Next.js, dan solusinya cukup satu baris di next.config.js.

Solusi cepat

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

Build ulang, deploy folder out/ yang baru, dan /about akan jalan di static file server mana pun.

Kenapa URL-nya 404

Secara default, export menulis satu file HTML per route, dengan nama sesuai route-nya:

out/
├── 404.html
├── about.html
├── blog/
│   └── hello.html
└── index.html

Klik <Link> jalan karena router Next.js melakukan navigasi di browser. Router mengambil file data route-nya (about.txt), bukan memuat /about sebagai halaman. Kunjungan langsung atau refresh mengirim request sungguhan ke /about. Static server biasa mencari file atau folder bernama about, tidak menemukan keduanya, lalu mengembalikan 404. Server tidak tahu bahwa /about seharusnya berarti about.html.

Ini hasil export default yang dilayani dengan python3 -m http.server:

/              200
/about         404
/about/        404
/about.html    200
/blog/hello    404

Apa yang diubah trailingSlash: true

Dengan trailingSlash: true, setiap route mendapat folder sendiri dengan index.html di dalamnya:

out/
├── 404.html
├── 404/
│   └── index.html
├── about/
│   └── index.html
├── blog/
│   └── hello/
│       └── index.html
└── index.html

Semua static server tahu harus melayani index.html untuk sebuah folder, jadi server Python yang sama sekarang mengembalikan:

/              200
/about         301  → /about/
/about/        200
/blog/hello    301  → /blog/hello/
/blog/hello/   200

Server me-redirect /about ke /about/, lalu melayani halamannya. <Link> juga merender href="/about/", jadi link internal langsung mengarah ke URL kanonis tanpa redirect.

Blog ini juga berjalan sebagai static export Next.js dengan trailingSlash: true karena alasan yang sama.

Atau perbaiki di sisi server

Kalau kamu mau tetap memakai URL tanpa garis miring di akhir, biarkan config-nya dan ajari server untuk mencoba .html. Di nginx:

location / {
  try_files $uri $uri.html $uri/ =404;
}
error_page 404 /404.html;

Hasilnya terhadap export default:

            nginx biasa   dengan try_files
/about      404           200
/blog/hello 404           200
/nope       404           404

/about/ dengan garis miring tetap 404 di sini, karena tidak ada folder about/. Kalau orang menautkan situs kamu dengan garis miring di akhir, trailingSlash: true adalah solusi yang lebih simpel.

Di S3 atau bucket lain tanpa aturan rewrite, cara ini tidak bisa dipakai, jadi pakai trailingSlash: true.

Kenapa jalan di lokal tapi rusak di production

npx serve out otomatis memetakan /about ke about.html. Terhadap export default, server ini mengembalikan 200 untuk /about, /about/, dan /blog/hello, jadi bug-nya tidak pernah muncul saat dites di lokal. Sebagian host melakukan pemetaan yang sama dan sebagian tidak. Sebelum deploy ke tempat baru, tes dengan server yang tidak melakukannya, misalnya python3 -m http.server dari dalam out/.

next export sudah dihapus

Jawaban lama menyuruh kamu menjalankan next build && next export. Di Next.js versi sekarang, command itu gagal:

`next export` has been removed in favor of 'output: export' in next.config.js.

Set output: 'export' di config lalu jalankan next build. Hasil export-nya ada di out/.

Kesalahan yang sering terjadi

Deploy folder out/ yang lama. trailingSlash mengubah file di disk, jadi kamu harus build ulang. Pastikan out/about/index.html ada sebelum upload.

Menulis link manual tanpa garis miring. <a href="/about"> biasa tetap jalan lewat redirect, tapi setiap klik butuh satu round trip tambahan. Pakai <Link>, atau tulis garis miringnya sendiri.

Mengubah setting di situs yang sudah live tanpa redirect. Pindah ke trailingSlash: true mengubah semua URL kanonis dari /about ke /about/. Mesin pencari menganggap keduanya halaman berbeda, jadi pastikan URL lama ter-redirect (static server biasanya melakukannya untuk folder, seperti contoh di atas) dan update sitemap kamu.

Kesimpulan

Static export Next.js mengembalikan 404 saat dikunjungi langsung karena /about disimpan sebagai about.html, dan static server tidak menambahkan ekstensinya. Set trailingSlash: true supaya setiap route menjadi about/index.html, atau tambahkan try_files $uri $uri.html di nginx kalau kamu memegang server-nya.

Referensi