Skip to content

fix(deploy): serve static files and prerendered pages from Cloudflare assets - #660

Merged
Brooooooklyn merged 6 commits into
voidzero-dev:mainfrom
serkodev:fix/static-deploy-asset-first
Nov 2, 2026
Merged

Brooooooklyn merged 6 commits into
voidzero-dev:mainfrom
serkodev:fix/static-deploy-asset-first

Conversation

@serkodev

@serkodev serkodev commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Fix #659

On native Cloudflare deploys, static files and prerendered pages no longer start the Worker. Paths with server code still start it. Hashed chunks keep the immutable cache policy through a generated _headers file.

request ──► Workers Static Assets
             │
             ├─ path in run_worker_first? ──► Worker (server code, /__void/*)
             ├─ file matches ─────────────► served free, no Worker
             └─ no file ──────────────────► Worker (not_found_handling: none)

Fully static deploys

App has run_worker_first
no edge rules ["/__void", "/__void/*"]
edge rules, alwaysUseHttps, public _headers / _redirects true (as before)

Void writes this value itself, as before. An authored cloudflare.assets.run_worker_first is still ignored on this path.

Hybrid output: "static" builds

  • run_worker_first lists only paths with server code: routes, WebSockets, and pages with a .server.ts file, parameters, or prerender = false.
  • Each pattern is widened to its static prefix (/posts/:slug → /posts/*). A dynamic first segment keeps today's behaviour.
  • Auth, live updates, middleware, routing.alwaysUseHttps or other site-wide rules keep today's behaviour.
  • A page served from assets answers POST with 405, not 404.

Docs

docs/guide/ssg.md "Deployment behavior" now says which pages skip the Worker and what keeps them on it.

Tests

  • Real build of playground/static-pages with a new page without a server module: Miniflare serves /plain from its file and sends /about to the Worker.
  • Unit and Miniflare tests for the rule planner, limits, and the static edge routing.

🤖 Generated with Claude Code

serkodev and others added 6 commits November 2, 2026 13:22
…ic CF deploy"

Issue voidzero-dev#659 does not ask for this. It made a deploy that worked on main
fail when the authored value does not reach /__void/ready, and it applied
to only one of the three Cloudflare deploy paths. Void writes its own
run_worker_first again; honoring an authored value is a separate decision.

This reverts commit 957aee8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- docs/guide/ssg.md: say which pages and files skip the Worker on
  Cloudflare, and what keeps every request on it.
- Add a page without a server module to playground/static-pages and check
  through Miniflare that its file answers without the Worker.
- Reuse VOID_INTERNAL_WORKER_FIRST and drop a stale alwaysUseHttps comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Brooooooklyn
Brooooooklyn force-pushed the fix/static-deploy-asset-first branch from 58d434d to 5f4b19a Compare November 2, 2026 05:44
@cpojer
cpojer requested a review from Brooooooklyn November 2, 2026 05:56
@Brooooooklyn

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 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-11-02T07:09:17.244502Z 5f4b19a Manual request
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5f4b19a2a4

ℹ️ 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".

Comment thread packages/void/src/plugin-routing.ts Resolved
@Brooooooklyn
Brooooooklyn merged commit e1d6c5c into voidzero-dev:main Nov 2, 2026
18 checks passed
cpojer pushed a commit that referenced this pull request Nov 9, 2026
…dy covers (#763)

Since #660 (1.6.0), an `output: "static"` Pages build lists only the
paths with server code in `run_worker_first`, so prerendered pages and
public files are served without starting the Worker. Each pattern is
widened to its static prefix before the first parameter (`/blog/:slug` →
`/blog/*`). When one server path sits under another one's `/prefix/*`
rule, both rules are written. For example, with two dynamic pages under
`/blog/`:

```
pages/blog/[slug].tsx       -> /blog/*
pages/blog/tags/[tag].tsx   -> /blog/tags/*
```

`vp build` succeeds without a warning, but Cloudflare rejects the list.
`vp preview` exits with a Miniflare error, and `wrangler deploy` refuses
the built output with the same message:

```
Error: Invalid routes in `run_worker_first`:
'/blog/tags/*': rule '/blog/*' makes it redundant
```

A dynamic API route next to the starter's `routes/api/hello.ts` fails
the same way (`/api/*` and `/api/hello`). Apps without `output:
"static"`, and static apps that use middleware, auth, live updates,
`routing.alwaysUseHttps` or edge rules, get a list that starts with
`/**` and are not affected.

## Fix

The planner now leaves out every rule that a `/prefix/*` rule in the
list already matches. The wider rule sends the same requests to the
Worker, so routing does not change.

- This also covers server paths under the `/assets/*` rule that a build
adds when it cannot list its hashed files in `_headers`.
- `/proxy` stays next to `/proxy/*`, and `/api-docs` next to `/api/*`:
neither starts with the wider rule's `/prefix/`.

## Tests

- `packages/void/test/unit/asset-worker-bypass.test.ts`: nested
wildcards, exact paths and a catch-all under a wildcard, a path below a
trailing-wildcard route, and a server path under the `/assets/*` rule
each keep only the wider rule. Both new cases fail without this fix.
- `packages/void/test/integration/native-asset-cache-policy.test.ts`:
the `output: "static"` case passes the planner's list to Miniflare,
which checks `run_worker_first` with the same code as wrangler. It now
adds `/items/tags/:tag` and `/api/:name` next to `/items/:id` and
`/api/hello`, and checks that `/items/tags/new` and `/api/someone` reach
the Worker. Without this fix, Miniflare rejects the list (`'/api/hello':
rule '/api/*' makes it redundant`).

## Verification

- `vp test run`: 788 files pass, 1 skipped (16,467 tests pass, 30
skipped).
- `vp run check`: 33/33 pass.
- By hand on a copy of `playground/static-pages` with
`pages/posts/tags/[tag]` next to `pages/posts/[slug]`, and
`routes/api/[name].ts` next to `routes/api/hello.ts`:
- Without this fix, `vp build` passes without a warning and writes
`/api/*`, `/api/hello`, `/posts/*` and `/posts/tags/*` to
`run_worker_first`. `vp preview` exits with `'/api/hello': rule '/api/*'
makes it redundant` and `'/posts/tags/*': rule '/posts/*' makes it
redundant`, and `wrangler deploy --dry-run` (4.158.0) fails with the
same errors.
- With it, the list keeps only `/api/*` and `/posts/*`. `vp preview`
starts: `/posts/tags/news` renders its page, `/api/hello` and
`/api/someone` answer from their own handlers, and a POST to `/plain`
still answers 405 from the asset layer. `wrangler deploy --dry-run`
passes.
- Not run: `void deploy` against Cloudflare.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.

Static Cloudflare deploys start the Worker on every request

2 participants