Skip to content

feat: split runtime/build server entries to exclude static routes from runtime bundle#1974

Draft
TiwariLokesh wants to merge 2 commits intowakujs:mainfrom
TiwariLokesh:feat/split-runtime-build-entry
Draft

feat: split runtime/build server entries to exclude static routes from runtime bundle#1974
TiwariLokesh wants to merge 2 commits intowakujs:mainfrom
TiwariLokesh:feat/split-runtime-build-entry

Conversation

@TiwariLokesh
Copy link

Summary

This PR addresses #1912 by introducing a proper architectural separation between runtime and build server entries.

Instead of pruning static route modules after build, this change prevents fully static routes from entering the runtime module graph in the first place.


Motivation

Currently, routes marked with render: "static" are still bundled into the runtime server output even though they are only needed during SSG. This increases the production bundle size (e.g. large OpenGraph libraries, WASM blobs) and can cause deployment size constraints in environments like Cloudflare Workers.

The previous workaround relied on post-build pruning. This PR removes that approach and replaces it with a cleaner graph-level separation.


What Changed

1. Runtime / Build Entry Split

Introduced two separate virtual server entries:

  • virtual:vite-rsc-waku/server-entry-runtime
  • virtual:vite-rsc-waku/server-entry-build

Runtime and build now generate independent module graphs.


2. Managed Mode Runtime Exclusion

In managed fsRouter mode:

  • Runtime entry excludes fully static page modules using import.meta.glob negative patterns.
  • Build entry keeps the full route graph to allow SSG to function normally.

3. Mode-Aware Router Resolution

  • getConfigs({ mode }) is now propagated through define-router.
  • Runtime paths resolve configs using mode: "runtime".
  • Build paths resolve configs using mode: "build".

4. Removed Post-Build Pruning

build-static-files.ts no longer performs file-level pruning.
Static route exclusion is now handled at graph-construction time instead of cleanup time.


Result

  • Static routes are still generated during SSG.
  • Static-only route modules are no longer included in the runtime server bundle (in managed mode).
  • No public API changes.
  • Backward compatible.
  • Cleaner architecture.

Notes

Static route detection in managed mode is heuristic-based (literal render: "static" detection) and conservative to avoid accidentally excluding dynamic routes.

Custom server entries may still bundle static modules if explicitly imported.

@vercel
Copy link

vercel bot commented Mar 1, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
waku Ready Ready Preview Mar 5, 2026 5:35am

Request Review

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 1, 2026

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

Thanks for working on it.

Instead of pruning static route modules after build, this change prevents fully static routes from entering the runtime module graph in the first place.

Sounds good.

We have waku/router on top of waku/minimal api. I wonder which is responsible to this capability. If it's waku/minimal related, we should work on it first, without caring waku/router much. (At least, the PR must be separated.)

import path from 'node:path';
import { EXTENSIONS, SRC_MIDDLEWARE, SRC_PAGES } from '../constants.js';

export const getManagedServerEntry = (srcDir: string) => {
Copy link
Member

Choose a reason for hiding this comment

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

I'm not sure if I 100% follow the idea, but it shouldn't be managed mode only. So, changing code here seems not ideal.

Comment on lines +644 to +645
getConfigs: async (context?: { mode?: 'runtime' | 'build' }) => {
const mode = context?.mode || 'runtime';
Copy link
Member

Choose a reason for hiding this comment

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

The change here is not nice and not acceptable. only define-router should be responsible to this capability.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks for pointing this out!

I've updated the implementation so that runtime/build filtering is handled entirely in define-router.
create-pages.tsx is now mode-agnostic as suggested.

Let me know if this looks better.

Copy link
Member

Choose a reason for hiding this comment

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

Do not change this in this PR.

@dai-shi
Copy link
Member

dai-shi commented Mar 3, 2026

Actually, while not sure, this might be somewhat related with #1790, which I'm hoping to tackle sometime soon.

@TiwariLokesh
Copy link
Author

Thanks for the feedback!

You're right - the current implementation mixes router-level responsibility with managed mode logic.

I'll revise the PR to:

  • revert the pnpm-workspace.yaml change
  • avoid modifying create-pages.tsx
  • move the runtime/build mode handling fully into define-router so that the capability is router-driven rather than managed-mode specific.

I'll push an updated version shortly.

@TiwariLokesh
Copy link
Author

Thanks for the detailed review!

I've pushed an update addressing the feedback:

  • Reverted changes to pnpm-workspace.yaml
  • Removed mode-aware logic from create-pages.tsx
  • Removed managed-mode filtering
  • Moved runtime/build filtering entirely into define-router

Now create-pages simply constructs the route configs and define-router handles runtime/build separation internally.

Build verification:
pnpm --filter waku compile:code
pnpm --filter waku compile:types

Please let me know if there’s anything else I should adjust.

Copy link
Member

@dai-shi dai-shi left a comment

Choose a reason for hiding this comment

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

Please let me know if there’s anything else I should adjust.

Don't expect this to be merged very soon. There are many things to consider some design decisions as I noted.

Meanwhile, make this PR minimal. Please don't change unrelated files. Review changes before pushing. For now, the quality feels AI generation level.

@@ -1,5 +1,4 @@
import { EXTENSIONS, SRC_MIDDLEWARE, SRC_PAGES } from '../constants.js';

Copy link
Member

Choose a reason for hiding this comment

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

remove changes in this file.

);
return resolved ? resolved : '\0' + source;
}
if (source === 'virtual:vite-rsc-waku/server-entry-build-inner') {
Copy link
Member

Choose a reason for hiding this comment

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

Any difference between -runtime-inner and -build-inner?

@dai-shi
Copy link
Member

dai-shi commented Mar 5, 2026

marking draft until we choose some design decisions.

@dai-shi dai-shi marked this pull request as draft March 5, 2026 06:35
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