Skip to content

perf(dev): prune NODE_ENV during dependency optimization - #2075

Merged
james-elicx merged 5 commits into
cloudflare:mainfrom
TheAlexLichter:perf/native-dep-optimize-define
Jun 16, 2026
Merged

perf(dev): prune NODE_ENV during dependency optimization#2075
james-elicx merged 5 commits into
cloudflare:mainfrom
TheAlexLichter:perf/native-dep-optimize-define

Conversation

@TheAlexLichter

Copy link
Copy Markdown
Collaborator

This PR improves cold start time by replacing NODE_ENV during Rolldown's prebundling step, resulting in less JavaScript dependencies during dev.

Over 10x10 runs:

  • main: 1417.5 ms
  • new branch: 1309.3 ms
  • Difference: 108.2 ms faster

@TheAlexLichter TheAlexLichter changed the title perf(dev): fold NODE_ENV during dependency optimization perf(dev): prune NODE_ENV during dependency optimization Jun 16, 2026
@james-elicx

Copy link
Copy Markdown
Member

/bigbonk review for issues

@ask-bonk ask-bonk Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Reviewed the dep-optimizer NODE_ENV pruning change. The approach is sound and matches Next.js intent (forcing NODE_ENV during dev so React/RSC deps drop the unused branch), and it correctly respects a user-supplied process.env.NODE_ENV define. The Vite 7 (esbuildOptions) vs Vite 8 (rolldownOptions.transform) split is handled cleanly, and resolvedNodeEnv is mode-aware so the optimizer define stays consistent with the environment. Nice coverage with both the config-shape unit tests and the dev-server integration test that inspects the actual deps_rsc/deps_ssr output.

A few minor observations below — none blocking.


export function serializeViteDefine(value: unknown): string {
if (typeof value === "string") return value;
return JSON.stringify(value) ?? "undefined";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Minor: JSON.stringify(value) returns string | undefined, so the ?? "undefined" fallback covers value === undefined (which happens when the user sets define: { "process.env.NODE_ENV": undefined }, since Object.hasOwn is true in that case). Worth confirming this is the intended behavior — it produces the bare replacement text undefined rather than the string "undefined". That matches how Vite treats define values (raw replacement text), so it looks correct, but a one-line comment explaining the ?? "undefined" branch would help future readers since it's a non-obvious edge case.

Comment thread tests/app-router-dev-server.test.ts Outdated
await response.arrayBuffer();

for (const envName of ["rsc", "ssr"]) {
const depsDir = path.join(server.config.cacheDir, `deps_${envName}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This assertion reads from Vite's internal cache layout (deps_<env> under cacheDir). It's a strong, meaningful check today, but it couples the test to a Vite implementation detail that could shift across Vite versions. Consider adding a short comment noting the dependency on Vite's deps cache directory naming so a future Vite bump that renames these dirs surfaces an understandable failure rather than a confusing readdir ENOENT.

]),
...(incomingInclude.length > 0 ? { include: incomingInclude } : {}),
rolldownOptions: { plugins: [depOptimizeAliasPlugin] },
...depOptimizeNodeEnvOptions,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Not a bug, just confirming intent: depOptimizeNodeEnvOptions is intentionally spread into the rsc/ssr/pages-server optimizeDeps but not into the client environment's optimizeDeps (client is a client consumer where Vite already replaces process.env.NODE_ENV by default). That's the right call. The top-level viteConfig.optimizeDeps here does get the define, and since it's also inherited by the client env in the non-app Pages path, the define is harmless there (client value is the same). Worth a one-liner noting that the define is deliberately scoped to server consumers, mirroring the helper's comment.

@ask-bonk

ask-bonk Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review posted successfully on PR #2075.

Summary

I reviewed PR #2075 (perf(dev): prune NODE_ENV during dependency optimization) and posted a batch review with one summary comment and three inline observations (all minor, none blocking).

Verdict: solid implementation, no bugs found.

Key findings:

  • The core approach is correct — pinning process.env.NODE_ENV in the dev dep optimizer lets server (RSC/SSR) dependencies drop the unused production/development branch, matching Next.js's behavior of forcing NODE_ENV during dev.
  • User-supplied process.env.NODE_ENV defines are correctly respected (Object.hasOwn check + serializeViteDefine passthrough).
  • The Vite 7 (esbuildOptions.define) vs Vite 8 (rolldownOptions.transform.define) split is handled cleanly, and spreading undefined for the absent variant is safe.
  • resolvedNodeEnv is mode-aware, so the optimizer define stays consistent with build/dev/test.
  • The client environment intentionally omits the define (client consumer already replaces NODE_ENV) — verified this is correct, not an oversight.
  • Tests pass; verified tests/build-optimization.test.ts NODE_ENV cases green, plus type/lint check on the new helper file is clean.

Minor observations raised:

  1. serializeViteDefine's ?? "undefined" edge case (user sets the key explicitly to undefined) could use an explanatory comment.
  2. The dev-server test couples to Vite's internal deps_<env> cache dir layout — suggested a comment noting that Vite-version dependency.
  3. Confirmed the deliberate scoping of the define to server consumers and suggested a clarifying one-liner.

github run

@TheAlexLichter

Copy link
Copy Markdown
Collaborator Author

Decoupled the test and added comments 👍

@james-elicx
james-elicx enabled auto-merge (squash) June 16, 2026 12:40
@pkg-pr-new

pkg-pr-new Bot commented Jun 16, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@vinext/cloudflare@2075
npm i https://pkg.pr.new/vinext@2075

commit: 9a4736e

@james-elicx
james-elicx merged commit f0e6be7 into cloudflare:main Jun 16, 2026
45 checks passed
@TheAlexLichter
TheAlexLichter deleted the perf/native-dep-optimize-define branch June 16, 2026 12:43
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