Starlove
Starlove

Reputation: 21

Next.js: Client-side exception and 404 error for static chunks in production, working fine in development

I am facing a peculiar issue with my Next.js application. The problem appears only in the production environment. In the development environment, everything works fine, but in production, I encounter a client-side exception and 404 errors for some static chunks.

Error Details

In the production environment, I get the following error: Application error: a client-side exception has occurred (see the browser console for more information).

Error screenshot

The browser console shows:

GET https://starblogs-trial.in/_next/static/chunks/app/posts/%5Bslug%5D/page-9f2de8d9ba04381a.js 404 (Not Found) ChunkLoadError: Loading chunk 333 failed. (error: https://starblogs-trial.in/_next/static/chunks/app/posts/%5Bslug%5D/page-9f2de8d9ba04381a.js) at l.f.j (webpack-84ef18324f9abbfd.js:1:3428) at webpack-84ef18324f9abbfd.js:1:1427 at Array.reduce () at l.e (webpack-84ef18324f9abbfd.js:1:1393) at self.next_chunk_load (596-6aee3da8cc55e0f0.js:1:5775) at 596-6aee3da8cc55e0f0.js:9:5750 at 596-6aee3da8cc55e0f0.js:9:5973 at t (596-6aee3da8cc55e0f0.js:9:6176)

Description

In the development environment, everything works perfectly. When I click on a blog post, the data is fetched from the database and displayed correctly. In production, the server logs indicate that the data is fetched correctly, but when trying to access certain properties, the application crashes.

Data structure

data looks like:

{
  "id": "sdfsdfsdfsd3623423432r5b327quqz8",
  "createdAt": "2024-06-27T13:11:36.112Z",
  "slug": "beautiful-places",
  "title": "Beautiful places",
  "desc": "<p>Contrary to popular belief, Lorem Ipsum is not simply random text...</p>",
  "img": "https://firebasestorage.googleapis.com/v0/b/.........",
  "views": 167,
  "catSlug": "travel",
  "userEmail": "[email protected]",
  "user": {
    "id": "sdfsdfsdfsd3623423432r5b327quqz8",
    "name": "John Doe",
    "email": "[email protected]",
    "emailVerified": null,
    "image": "https://lh3.googleusercontent.com/....."
  }
}

Folder structure

src └── app └── posts └── [slug] └── page.jsx

Page.jsx code

import React from 'react'
import styles from './singlePage.module.css'
import Image from 'next/image'
import Comments from '@/components/comments/Comments'
import Menu from '@/components/menu/Menu'
import DOMPurify from 'isomorphic-dompurify'

const getData = async (slug) => {
  const res = await fetch(`${process.env.NEXTAUTH_URL}/api/posts/${slug}`, {
    cache: 'no-store',
  })
  if (!res.ok) {
    throw new Error('Failed')
  }
  return res.json()
}

const SinglePage = async ({ params }) => {
  const { slug } = params
  let data = null
  try {
    data = await getData(slug)
  } catch (error) {
    console.error('Error fetching post data:', error)
  }
  return (
    <div className={styles.container}>
      <div className={styles.infoContainer}>
        <div className={styles.textContainer}>
          <h1 className={styles.title}>{data?.title}</h1>
          <div className={styles.user}>
            {data?.user?.image && (
              <div className={styles.userImageContainer}>
                {/* <Image
                  src={data.user.image}
                  alt="user image"
                  fill
                  className={styles.avatar}
                /> */}
              </div>
            )}
            <div className={styles.userTextContainer}>
              <span className={styles.username}>{data?.user?.name}</span>
              <span className={styles.date}>{data?.createdAt}</span>
            </div>
          </div>
        </div>
        {data?.img && (
          <div className={styles.imageContainer}>
            {/* <Image src={data.img} alt="" fill className={styles.image} /> */}
          </div>
        )}
      </div>
      <div className={styles.content}>
        <div className={styles.post}>
          <div
            className={styles.description}
            dangerouslySetInnerHTML={{
              __html: DOMPurify.sanitize(data?.desc),
            }}
          />
          <div className={styles.comment}>
            {/* <Comments postSlug={slug} /> */}
          </div>
        </div>
        {/* <Menu /> */}
      </div>
    </div>
  )
}
export default SinglePage

Network screenshot

enter image description here

Observations

Steps Taken

Next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'lh3.googleusercontent.com',
      },
      {
        protocol: 'https',
        hostname: 'firebasestorage.googleapis.com',
      },
    ],
  },
  env: {
    GOOGLE_ID: process.env.GOOGLE_ID,
    GOOGLE_SECRET: process.env.GOOGLE_SECRET,
    NEXTAUTH_URL: process.env.NEXTAUTH_URL,
    NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
    DATABASE_URL: process.env.DATABASE_URL,
    FIREBASE: process.env.FIREBASE,
  },
}

module.exports = nextConfig

Request for Help

I am looking for guidance on the following:

Any help would be greatly appreciated!

Upvotes: 0

Views: 887

Answers (1)

Kota Sugawara
Kota Sugawara

Reputation: 11

I encountered the same issue. I hope this helps.

Are you using Nginx as your server? If so, the problem lies in the /%5Bslug%5D/ part of the app router. Usually, the [slug] portion in links (written as /%5Bslug%5D/) cannot be read by Nginx, resulting in 503 or 404 errors.

Solution 1: Add a redirect in next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
  async redirects() {
    return [
      {
        source: '/_next/static/chunks/app/%5Bslug%5D/:path*',
        destination: '/_next/static/chunks/app/[slug]/:path*',
      },
    ]
  },
}

module.exports = nextConfig

This redirects the encoded URL to a converted link where: "%5B" → "[" "%5D" → "]"

Solution 2: If it's not a static site, add a redirect in middleware.ts (recommended)

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const url = request.nextUrl.clone()
  
  if (url.pathname.includes('/_next/static/chunks/app/')) {
    const decodedPathname = decodeURIComponent(url.pathname)
    if (url.pathname !== decodedPathname) {
      url.pathname = decodedPathname
      return NextResponse.rewrite(url)
    }
  }

  return NextResponse.next()
}

export const config = {
  matcher: [
    '/_next/static/chunks/app/:path*'
  ]
}

This solution performs the redirect internally, making it robust against page reloads. By using NextResponse.rewrite(url), you can internally rewrite the URL.

I hope this solves your problem!

Upvotes: 1

Related Questions