Skip to content

fix(router): reject HEAD exports and give each route file its own loader name - #612

Merged
Brooooooklyn merged 2 commits into
fix/secret-sync-dotenvfrom
fix/router-head-and-loader-names
Oct 27, 2026
Merged

Brooooooklyn merged 2 commits into
fix/secret-sync-dotenvfrom
fix/router-head-and-loader-names

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Problem

Two separate mistakes could each make the generated route module (virtual:void-routes) fail to load. When that happens, every request fails, in dev and in production.

  1. export const HEAD in a route file. The compiler wrote app.head(...), but Hono has no head method, so the module threw on load. Hono already answers HEAD requests with the GET handler.
  2. Loader names that repeat. Each loader was named after its file path, with every non-ASCII-letter/digit replaced by _. So api/user-list.ts and api/user_list.ts, or blog/你好.md and blog/世界.md, declared the same const twice (SyntaxError).
before                                   after
routes/ping.ts: GET + HEAD               routes/ping.ts: GET + HEAD
  -> app.head(...)  TypeError on load      -> scan error: "HEAD requests are answered
                                              by the GET handler; remove the HEAD export."

api/user-list.ts -> _load_api_user_list_ts    api/user-list.ts -> _load_api_user_list_ts
api/user_list.ts -> _load_api_user_list_ts    api/user_list.ts -> _load_api_user_list_ts_2
   (declared twice -> SyntaxError)               (prerender collector uses the same names)

What changed

  • router/scan.ts: route scanning stops with a clear error that names the file when it exports HEAD.
  • router/compile.ts: new createIdentifierNames() helper. It keeps the old cleaned-up name and adds _2, _3, ... only when a name would repeat. Route loaders use one map. Page loaders, markdown head functions and the prerender path collector share a second map.
  • docs/guide/server-routing.md: one line saying GET also answers HEAD.

Two commits: the HEAD fix first, then the loader names.

Tests

  • A route that exports HEAD fails the scan with the new message.
  • api/user-list.ts + api/user_list.ts compile, and the output parses with oxc semantic checks on.
  • Two CJK .md pages and two CJK server pages (one prerendered) get their own names, and the prerender collector calls the same loader as the page route.
  • Mutation checks: turning off the HEAD check, the counter, the shared prerender map, or the route map each makes a new test fail.

Choices to check

  • A HEAD export is now a scan error, not dropped quietly. Such apps crash on load today, so nothing that works now breaks.
  • Page names are keyed by componentId, which is already unique per page, so existing names such as _pload_index stay the same.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T08:07:23.199385Z 8665f77 New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@Brooooooklyn

Copy link
Copy Markdown
Member Author

@codex review

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

🚀 Deploying Preview to Cloudflare 🚀

Preview URL: https://fix-router-head-and-loader-names-void-cloud.voidzero-docs.workers.dev (commit 8665f77)

This URL reflects your latest Preview deployment

Preview Deployments by commit

Status Deployment URL Commit Updated (UTC) See this deployment's details
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://24e7e5dc-void-cloud.voidzero-docs.workers.dev 8665f77 2026-10-27T08:06:55.087Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://814ad473-void-cloud.voidzero-docs.workers.dev 580d966 2026-10-27T07:55:17.924Z Visit the dashboard ↗
  • Build: Success ✅
  • Deployment: Success ✅

View logs ↗
https://d0304c37-void-cloud.voidzero-docs.workers.dev dd20f96 2026-10-27T07:21:24.923Z Visit the dashboard ↗

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: dd20f96aa5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Brooooooklyn
Brooooooklyn force-pushed the fix/router-head-and-loader-names branch from dd20f96 to 580d966 Compare October 27, 2026 07:54
@Brooooooklyn
Brooooooklyn changed the base branch from main to fix/secret-sync-dotenv October 27, 2026 07:55
@Brooooooklyn
Brooooooklyn added this pull request to stack #618 October 27, 2026 07:56
Brooooooklyn and others added 2 commits October 27, 2026 16:05
A route file that exported HEAD made the generated route module call
app.head(), which Hono does not have. The module threw on load, so every
request to the app failed in dev and in the deployed Worker. Hono already
answers HEAD requests with the GET handler, so a HEAD handler could never
run anyway.

Route scanning now stops with a clear error that names the file and says
to remove the HEAD export. The server routing guide notes that GET also
answers HEAD.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generated route module named each loader after its file path with
every character other than an ASCII letter or digit turned into "_".
Two route files such as api/user-list.ts and api/user_list.ts, or two
page files whose non-ASCII names have the same length (blog/你好.md and
blog/世界.md), produced the same const twice. The module then failed to
parse with "Identifier has already been declared", which broke dev and
build.

Loader and markdown head names now come from one name map per kind. A
name that would repeat gets a numeric suffix, and the prerender path
collector uses the same names as the page routes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Brooooooklyn
Brooooooklyn force-pushed the fix/router-head-and-loader-names branch from 580d966 to 8665f77 Compare October 27, 2026 08:05
@Brooooooklyn
Brooooooklyn enabled stacked auto-merge (squash) October 27, 2026 08:34
stacked auto-merge was automatically disabled October 27, 2026 08:34

Auto-merge was disabled for another pull request in the stack

@Brooooooklyn
Brooooooklyn merged commit 3c90fb9 into main Oct 27, 2026
19 checks passed
@Brooooooklyn
Brooooooklyn deleted the fix/router-head-and-loader-names branch October 27, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants