feat(config): static vite config extraction for run config#679
Merged
branchseer merged 14 commits intomainfrom Mar 12, 2026
Merged
feat(config): static vite config extraction for run config#679branchseer merged 14 commits intomainfrom
run config#679branchseer merged 14 commits intomainfrom
Conversation
fd94982 to
9052846
Compare
👷 Deploy Preview for viteplus-staging processing.
|
474fef7 to
ecbafe2
Compare
…n` config Add a new `vite_static_config` crate that uses oxc_parser to statically extract JSON-serializable fields from vite.config.* files without needing a Node.js runtime. The `VitePlusConfigLoader` now tries static extraction first for the `run` config and falls back to NAPI only when needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The config file resolution order was .ts first, but Vite resolves .js, .mjs, .ts, .cjs, .mts, .cts — matching that order now. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…olver Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
resolve_static_config now returns Option<FxHashMap<..., StaticFieldValue>>: - None: config is not analyzable (no file, parse error, no export default, or exported value is not an object literal) — caller should fall back to NAPI - Some(map): config was successfully analyzed - Json(value): field extracted as pure JSON - NonStatic: field exists but value is not a JSON literal - key absent: field does not exist in the config Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tching - PropertyKey::static_name() replaces property_key_to_string and property_key_to_json_key - TemplateLiteral::single_quasi() replaces manual quasis/expressions check - Expression::is_specific_id() replaces is_define_config_call helper - ArrayExpressionElement::is_elision()/is_spread() replaces variant matching - ObjectPropertyKind::is_spread() replaces variant matching Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for CommonJS config files:
- module.exports = { ... }
- module.exports = defineConfig({ ... })
Refactored shared config extraction into extract_config_from_expr,
used by both export default and module.exports paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace umbrella `oxc` dependency with `oxc_ast`, `oxc_parser`, and `oxc_span` for more precise dependency tracking. Add README documenting supported patterns, config resolution order, return type semantics, and limitations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…Value Rewrite f64_to_json_number to follow JSON.stringify semantics using serde_json's From<f64> for the NaN/Infinity→null fallback, and i64::try_from for safe integer conversion. Rename StaticFieldValue to FieldValue for brevity. Add tests for overflow-to-infinity and -0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…onfig file Two improvements to static config extraction: 1. When no vite.config.* file exists in a workspace package, resolve_static_config now returns an empty map (instead of None). The caller sees no `run` field and returns immediately, skipping the NAPI/JS callback. This eliminates ~165ms cold Node.js init + ~3ms/pkg warm overhead for monorepo packages without config files. 2. Support defineConfig(fn) where fn is an arrow function or function expression. The extractor locates the return expression inside the function body and extracts fields from it. Functions with multiple return statements are rejected as not statically analyzable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r lookup
Handles the common pattern where the config object is assigned to a variable
before being exported or returned:
const config = defineConfig({ ... });
export default config; // ESM indirect export
module.exports = config; // CJS indirect export
return config; // inside defineConfig(fn) callback
Resolution scans top-level VariableDeclarator nodes by name (simple binding
identifiers only; destructured patterns are skipped). One level of indirection
is supported — chained references (const a = b; export default a) are not
resolved and fall back to NAPI as before.
Fixes tanstack-start-helloworld's ~1.3s config load time.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…dentifier lookup" This reverts commit ecc3fc2.
`{ a: 1, ...x, b: 2 }` — the spread may override `a`, so `a` is now
marked NonStatic. Fields declared after the spread (`b`) are unaffected
since they win over any spread key. Unknown keys from the spread are
still not added to the map.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
`{ a: 1, [key]: 2, b: 3 }` — `[key]` could resolve to `'a'` and
override it, so `a` is now marked NonStatic. Same logic as spreads.
Fields after the computed key are unaffected (they explicitly win).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
45787e4 to
9cce0f4
Compare
fengmk2
approved these changes
Mar 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Add new
vite_static_configcrate that usesoxc_parserto statically extract JSON-serializable fields fromvite.config.*files without executing JavaScriptPerformance
Measured using Chrome trace instrumentation (PR #663).
On a cache hit,
vp runloads the config, validates the fingerprint, and streams cached output — no build work. Before this PR, config loading required a NAPI round-trip to evaluate the config file. With static extraction that cost drops to ~0ms.vp runend-to-end time (cache hit)Summary
VitePlusConfigLoadernow tries static extraction first for therunconfig, falling back to NAPI-based resolution only when the config cannot be statically extractedexport default { ... }— bare object literalexport default defineConfig({ ... })— direct callexport default defineConfig(() => ({ ... }))— concise arrow bodyexport default defineConfig(fn)— block body with single returnmodule.exports = ...— CJS equivalentsvite.config.*file exists, returns an empty map immediately (skips NAPI entirely)Test plan
vite_static_configpassvite-plus-clitests passcargo fmt --checkpassescargo shearreports no unused dependenciescargo clippyclean (no new warnings)🤖 Generated with Claude Code