fix(build): define process.browser per environment - #2899
Conversation
|
/bigbonk review for issues |
commit: |
|
UnknownError: ProviderInitError |
|
@james-elicx Bonk workflow was cancelled. View workflow run · To retry, trigger Bonk again. |
|
|
/bigbonk review for issues |
Performance benchmarksCompared 0 improved · 0 regressed · 6 within ±1.5%
View detailed results and traces 🟢 improvement · 🔴 regression · ⚫ change below 1.5% · paired base/head |
|
/bigbonk review for issues |
/bigbonk reviewReviewed at head No blocking issues found. The design is sound and the risky parts hold up under scrutiny. Notes below are analysis + a couple of low-severity robustness observations, not merge blockers. What I checked closelyValue-semantics of the Dev/prod parity. Server envs get Cache key correctness. The transform cache variant
Filter broadening. The Low-severity observations (non-blocking)
Nice work — the scope-aware binding checks, escaped/computed/optional/commented member spellings, and nested |
|
Posted the review to PR #2899. SummaryReviewed PR #2899 ( No blocking issues found. The design is correct. Key findings:
Two low-severity, non-blocking observations were noted (a theoretically-unreachable empty-effects crash guard, and keeping the "analysis-only" invariant documented for the operand folds). |
20f3b49 to
213eebe
Compare
|
/bigbonk review for issues |
/bigbonk reviewReviewed at head No blocking issues. The architecture is correct and the risky part — the lossy Why the lossy folds are safe (verified)The effect-preserving folds are gated behind Notes (non-blocking)
What I checked and confirmed good
Solid work. |
|
Posted my review to PR #2899. SummaryReviewed No blocking issues found. The design is correct:
Two low-severity, non-blocking notes:
|
|
/bigbonk review for issues |
|
/bigbonk review for issues Please review exact current head |
/bigbonk reviewReviewed exact head The design is correct and the previously-flagged invariant chain ( One new finding introduced by the performance-filter delta.
|
| input | length | time |
|---|---|---|
| n=10k | 220 KB | 145 ms |
| n=20k | 440 KB | 567 ms |
| n=40k | 880 KB | 2268 ms |
Doubling the input ~quadruples the time — clean quadratic. A ~1 MB server file with only process.env.* refs takes ~3.5 s just for the filter check.
This matters because this transform.filter runs over every module in every environment, and the filter was deliberately broadened here to run on more files. Server code and bundled deps that reference process.env.* heavily but never mention browser are exactly the common case that now pays the worst-case cost. Files that do contain a browser token hit the first process match immediately and return fast (~0.2 ms), so the slow path is specifically "lots of process, no browser" — a realistic shape for large server bundles.
Note the filter is also order-sensitive (process must precede browser), while the internal early-out in replaceConsumerEnvironmentConditions (typeof-window.ts:239-241) already uses the order-independent /\bprocess\b/.test(code) && /\bbrowser\b/.test(code). So the filter is doing strictly more work than the precise gate it feeds. The straightforward fix is to keep the filter branch linear — e.g. match \bprocess\b alone (no [\s\S]*? bridge) and let the existing order-independent early-out do the precise rejection, or run two separate anchored .test() calls. A single lookahead-pair rewrite does not fix it (it is also quadratic/worse). Severity: low — it is a build/scan-time throughput regression, not a correctness bug, and only bites large process-heavy/browser-free files.
Confirmed good (no action)
- Lossy operand folds are analysis-only.
pruneUnreachableImportsis set only whenscansImports(build.write === false), andreplaceProcessBrowseris gated on the same flag (index.ts:5975-5977, 5993). Executed dev/prod code gets value-preservingprocess.browsersubstitution from Vite's per-environmentdefine; the "preserves logical operand values outside import analysis" test pins the non-scan path to value-preserving output. effects.filter(hasRange)cannot empty a non-emptyeffectsarray — every effect is aLogicalExpression.left, whichparseAstalways ranges. Theeffects[0]/effects.at(-1)!accesses (typeof-window.ts:318, 322, 353, 379) are safe.- Per-environment define uses
consumer === "client"(index.ts:5943, 5983), soworker/rsc/ssrall correctly getfalse; the optimizerrolldownOptions.transform.definemirrors it. The build-optimization "consumer type across client, RSC, SSR, and Worker" and "survives Vite's environment config merge" tests confirm the define merges with (not replaces) the NODE_ENV/JSX optimizer policy. compiler.define/defineServerconflict rejection (|| key === "process.browser", index.ts:2383, 2398) correctly closes the gapkey in definescan't catch, since the per-env define is injected inconfigEnvironment, not the config-timedefinesobject. Matches Next.js reservingprocess.browser.- Cache variant key
${typeofWindow|-}:${processBrowser|-}co-varies with scan/non-scan mode, so scan and non-scan passes for one env never collide. - Scope handling (shadowed
process/windowbindings, params, switch/loop/static-block/namespace scoping) and escaped/computed/optional/commented member spellings are covered by tests and hold up. - Production branch pruning verified end-to-end:
__BROWSER_ONLY_MODULE__is pruned from RSC/SSR but kept on the client, and the universal side-effect module on the left of&& process.browseris preserved.
No blocking issues. The one filter-complexity note above is the only thing worth addressing.
|
Posted my review to PR #2899. SummaryReviewed exact head One new finding, introduced by the performance-filter delta:
Confirmed correct (no action): the analysis-only invariant chain for the lossy folds, the theoretically-empty No blocking issues — the filter-complexity note is the only thing worth addressing. |
|
/bigbonk review for issues Please review exact current head |
/bigbonk reviewReviewed exact head The prior quadratic finding is fully resolved. No blocking issues. The fix resolves the quadratic filter (verified)The commit replaces the O(n²)
The old branch quadruples per doubling (clean quadratic); the new branch is flat regardless of size. The common server case — files with The broadened filter is still a correct superset of the precise gate (verified)Dropping the
Every input the gate accepts still passes the new filter:
So no transform is ever incorrectly skipped. The escaped-spelling cases ( Everything from prior reviews still holdsThe rest of the PR is unchanged from the previously-approved head, and the invariant chain is intact: the lossy The two low-severity non-blocking notes from earlier reviews still stand (the load-bearing-but-implicit "effect-folding is analysis-only" invariant would benefit from a one-line comment; Solid, targeted fix. |
|
Posted the review to PR #2899. SummaryReviewed exact head The prior quadratic finding is fully resolved. No blocking issues. Key verifications:
All 34 relevant tests pass and |
|
/bigbonk review for issues Please review exact current head |
/bigbonk reviewReviewed exact head No blocking issues. The new local-syntax filter is correct, linear, and a proper superset of the precise AST gate. The new filter is not quadratic (verified)The delta replaced the linear Unlike the earlier
The new The filter remains a correct superset of the precise gate (verified)The filter's only job is to be a fast superset of the order-independent internal gate in
So no foldable Over-admission is harmless (verified)The narrowing intentionally keeps two over-admitting branches: the standalone Everything from prior reviews still holds
The two long-standing low-severity, non-blocking notes still stand and are unaffected by this delta:
Clean, well-tested, targeted fix. No merge blockers. |
|
Posted my review to PR #2899. SummaryReviewed exact head No blocking issues found. The new selective local-syntax filter is correct, linear, and a proper superset of the precise AST gate. Key verifications:
Two long-standing low-severity non-blocking notes carry over (implicit "analysis-only" fold invariant would benefit from a comment; the unreachable empty- |
Summary
process.browserastruefor client consumers andfalsefor RSC, SSR, and Worker consumers, including each environment optimizerprocess.browserguards before plugin-RSC import analysis so browser-only conditional exports are not resolved from dead branchescompiler.defineandcompiler.defineServerentriesThis is the focused parent for the ESM-externals compatibility work in #2877; that PR will be stacked on this one after this draft is opened.
Validation
vp test run tests/build-optimization.test.ts tests/compiler-define.test.ts tests/process-browser-define.test.ts tests/type-of-window.test.ts tests/tsconfig-paths-vite8.test.ts tests/client-global-define.test.ts— 205 passed, 2 skippedvp check packages/vinext/src/index.ts packages/vinext/src/plugins/typeof-window.ts tests/build-optimization.test.ts tests/compiler-define.test.ts tests/process-browser-define.test.ts tests/type-of-window.test.ts tests/tsconfig-paths-vite8.test.ts vite.config.tsvp run vinext#buildFinal verification