Browse sections

root@kaus.com:~/blog$ cat github-pages-jekyll-next-trap.md

Lessons4 min read

The homepage loaded. The application did not.

A GitHub Pages deployment served the page text while dropping the JavaScript, CSS, and fonts under _next. The fix was an empty file. The lasting change was the definition of a successful deployment.

Updated

The key idea

Verify the artifact through its dependencies and one real interaction, not just the document that contains them.

Kbit · page guide
  1. 1 / 3

    The article is the primary path.

    Read top to bottom; figures and code-linked examples stay inside the narrative.

  2. 2 / 3

    Continue through related work.

    Use related writing or project links to keep the context connected.

  3. 3 / 3

    Return to the index at any point.

    Open the full Writing index to browse more topics.

The HTML passed the first check

The first deployment of this site's static export looked complete enough to pass a shallow check. The homepage text rendered and the console inspection reported no errors. A deeper network inspection found that the JavaScript chunks, CSS, and font files under _next were returning 404. The page had arrived. Its dependencies had not.

That left the interactive projects grid, search, and view controls without the client code they needed. The saved incident record is unusually useful because the apparent success and the actual failure came from different observations of the same deployment. The question was no longer whether the URL loaded. It was which part of the application the successful response had proved.

There was another build step after the build

Next.js had already produced the static export. The deployment then handed those generated files to a branch-based GitHub Pages publishing path that processed them through Jekyll. That second stage treated the underscore-prefixed _next directory as something to omit. The original export could be correct while the served artifact was incomplete.

Static HTML can contain readable text before any client JavaScript executes. That is normally a strength: a reader can see content promptly, and useful pages can survive limited JavaScript availability. It also makes the document an incomplete health check. The presence of headings says very little about whether code needed for a filter or search interaction was delivered.

The incident concerns this site's Jekyll-processing publishing path. It should not be generalized to every Pages deployment, especially a different workflow that uploads an already-built artifact directly. The important boundary is the transformation between local output and what the host actually serves.

Required placement in this site's static-export pipelinetext
source
  public/.nojekyll          empty marker, copied by the export

published root
  .nojekyll                keep this at the serving root
  index.html
  _next/
    static/                generated JavaScript, CSS, and fonts

Put the repair where the artifact comes from

The repair was an empty .nojekyll file at the published root. For this site, placing it under public means the normal export carries it into out. That makes the repair part of the generated artifact rather than a manual action someone must remember in a deployment directory.

Placement matters more than contents. A marker sitting in the source checkout but missing from the published root would not address the failure. A deployment procedure that forgets dotfiles could reintroduce the same problem even while the source still appears correct. The handoff between export and publication therefore needs to preserve the complete artifact.

The recorded verification after the repair found that the previously missing assets returned 200 and the affected project and exploration interfaces worked again. That is the supported outcome of the incident. It does not establish that a future release is healthy just because the marker remains checked in.

Follow the dependency chain to a user action

My deployment check now distinguishes local generation, public delivery, and behavior. A successful build establishes that the framework generated output. Fetching the public HTML establishes that a document is served. Requesting the asset URLs referenced by that document tests whether its specific dependencies are present. Exercising search or a filter tests a path through the delivered application.

Those observations complement one another. Checking a remembered chunk filename is weaker than checking the assets referenced by the deployed document, because build filenames can change. Checking a client interaction only on a local development server leaves the publishing transformation untested. An empty console is useful evidence, but the original incident shows why it cannot carry the whole conclusion.

The small size of the fix makes this an easy bug to underestimate. There was no complex application rewrite to review, only a missing instruction at a packaging boundary. The durable repair was to stop treating a successful document response as a successful release. For a static application, the deployable unit includes the document, its dependencies, and the behavior those dependencies enable.

Sources & further reading

  1. GitHub Pages publishing sources ↗

    Official documentation for branch publishing and bypassing Jekyll with .nojekyll.

  2. Next.js static exports ↗

    Official documentation for the generated HTML and assets served by a static host.

  3. Exercise the projects interface

    Project selection and search are examples of behavior that depends on delivered client assets.