Skip to content

fix(app-router): ignore very dynamic requests during build analysis#12

Closed
NathanDrake2406 wants to merge 1 commit into
mainfrom
nathan/dynamic-requests
Closed

fix(app-router): ignore very dynamic requests during build analysis#12
NathanDrake2406 wants to merge 1 commit into
mainfrom
nathan/dynamic-requests

Conversation

@NathanDrake2406

Copy link
Copy Markdown
Owner

Overview

Field Details
Goal Match Next.js App Router build behaviour for very dynamic import(...) and require(...) calls.
Core change Add a pre-transform that removes only requests with no static path part from build graph analysis.
Main boundary Static or partly static requests still flow through existing Vite/CommonJS analysis. Fully dynamic requests remain runtime-only and fail only if executed.
Primary files packages/vinext/src/plugins/ignore-dynamic-requests.ts, packages/vinext/src/index.ts, tests/build-optimization.test.ts
Expected impact App Router page and route builds no longer fail on guarded require(dynamic) / import(dynamic) patterns that Next.js accepts.

Why

App Router production builds must separate graph-analysis inputs from code that is only meaningful at runtime. Next.js/Turbopack treats requests with no static known path part as "very dynamic" and, with ignore_dynamic_requests, avoids adding them to the module graph. Vinext violated that boundary because vite-plugin-commonjs tried to expand require(dynamic) as a static glob, causing a build-time failure even when the code was unreachable.

Area Principle / invariant What this PR changes
App Router build analysis Very dynamic requests should not become required static graph edges. Rewrites only require(...) calls that have no static request part to a runtime helper before CommonJS analysis.
Dynamic import(...) Vite should not warn or analyze requests that Next.js treats as runtime-only. Adds /* @vite-ignore */ only for imports with no static request part.
Compatibility Analyzable requests must keep existing behaviour. Leaves literals, non-empty templates, and expressions with static parts untouched.

What changed

Scenario Before After
require(dynamic) with no static path part Build failed in vite-plugin-commonjs with an invalid dynamic import error. Build succeeds and the request remains runtime-only.
import(dynamic) with no static path part Vite attempted dynamic request analysis. The import is marked with @vite-ignore.
require('./' + name) or import(./${name}) Existing static-part analysis path. Unchanged.
Maintainer review path
  1. packages/vinext/src/plugins/ignore-dynamic-requests.ts validates the request classification and transform boundaries.
  2. packages/vinext/src/index.ts places the plugin immediately before vite-plugin-commonjs, which is the failing analyzer.
  3. tests/build-optimization.test.ts ports the upstream dynamic-requests scenario at the production build boundary.
Validation
  • vp test run tests/build-optimization.test.ts tests/cjs.test.ts
  • vp check
  • vp env exec --node 24 ./scripts/run-nextjs-deploy-suite.sh /Users/nathan/Projects/vinext/.refs/nextjs-v16.2.6 --retries 0 -c 1 --debug test/e2e/app-dir/dynamic-requests/dynamic-requests.test.ts
  • Commit hook: formatting, lint/type checking, and knip
Risk / compatibility
  • Public API impact: none.
  • Runtime impact: only fully dynamic require(...) calls are redirected to a runtime helper that throws if executed, matching the intended runtime-only failure shape.
  • Build output impact: static and partly static request expressions continue to use the existing analyzer path.
  • Framework compatibility: intentionally follows Next.js/Turbopack's ignore_dynamic_requests behaviour for requests without a static known part.
Non-goals
  • This PR does not implement Turbopack's broader handling for dynamic new URL, filesystem, or child process request patterns.
  • This PR does not change the existing CommonJS transform for analyzable request expressions.

References

Reference Why it matters
Next.js dynamic-requests e2e test Upstream contract: guarded dynamic requests in pages and routes should not error.
Next.js ignore_dynamic_requests option Documents the intended semantics for requests without a static known part.
Turbopack dynamic import(...) handling Shows very dynamic imports become runtime dynamic expressions when ignored.
Turbopack dynamic require(...) handling Shows very dynamic requires become runtime dynamic expressions when ignored.

App Router production builds currently fail when a page or route module contains guarded require(dynamic) calls. That differs from Next.js, where requests with no static request part are ignored during graph analysis and only fail if executed at runtime.

The violated invariant was that bundler analysis should not turn unreachable, very dynamic requests into build-time failures. vite-plugin-commonjs tried to expand require(dynamic) as a static glob before the branch could remain runtime-only code.

Add a pre-transform that preserves directives, removes only very dynamic require calls from CJS graph analysis, and marks matching dynamic import calls with @vite-ignore. The regression builds both an App Router page and route module ported from Next.js dynamic-requests coverage.
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.

1 participant