Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Add package-manager overrides so that other packages use the Vite+ versions. Ali
```json
"overrides": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand All @@ -216,15 +216,15 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`:
```yaml
overrides:
vite: npm:@voidzero-dev/vite-plus-core@latest
vitest: 4.1.10
vitest: 4.1.11
```

Or, if you are using Yarn:

```json
"resolutions": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Help requests with additional arguments delegate to the underlying tool.
## `vp test --help --coverage`

```
vitest/4.1.10
vitest/4.1.11

Usage:
$ vitest [...filters]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ VITE+ - The Unified Toolchain for the Web
◇ Updated . to Vite+ <version>
• Node <version> pnpm <version>
• Dependencies:
vite-plus latest → <version>
vite → <version>
vite-plus latest → <version>
vite → <version>
vitest 4.1.10 → <version>
@vitest/browser-playwright 4.1.10 → <version>
@vitest/coverage-v8 4.1.10 → <version>
• Package manager settings configured
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ export default defineConfig({
"typescript/triple-slash-reference": "error",
"react/rules-of-hooks": "error",
"react/exhaustive-deps": "warn",
"react/static-components": "error",
"react/use-memo": "error",
"react/preserve-manual-memoization": "error",
"react/incompatible-library": "warn",
"react/immutability": "error",
"react/globals": "error",
"react/refs": "error",
"react/set-state-in-effect": "error",
"react/error-boundaries": "error",
"react/purity": "error",
"react/set-state-in-render": "error",
"react/unsupported-syntax": "warn",
"react/only-export-components": [
"error",
{
Expand Down
22 changes: 22 additions & 0 deletions crates/vp_cli_snapshots/tests/cli_snapshots/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,20 @@ impl CaseHome {
let vp_home = this.vp_home();
std::fs::create_dir_all(&vp_home).unwrap();
std::fs::create_dir_all(root.join("npm-global/lib")).unwrap();
// Pin pnpm's release-age gate off for every case. pnpm applies a
// default `minimumReleaseAge` and, on a real install, records the
// immature versions it auto-approved as exact `name@version` entries
// under `minimumReleaseAgeExclude` in the project's
// pnpm-workspace.yaml. That list is a function of npm publish times,
// not of anything a case asserts, so cases doing real installs (those
// unsetting `VP_SKIP_INSTALL`) would otherwise snapshot a block that
// appears only while a bundled dependency is under 24h old and
// vanishes once it ages out — green on the upstream-bump PR, red the
// next day. Only the global config file is honoured here; the npmrc
// key and `NPM_CONFIG_MINIMUM_RELEASE_AGE` are both ignored.
let pnpm_config_dir = this.xdg_config_home().join("pnpm");
std::fs::create_dir_all(&pnpm_config_dir).unwrap();
std::fs::write(pnpm_config_dir.join("config.yaml"), "minimumReleaseAge: 0\n").unwrap();
// Best-effort: if linking fails, the case downloads the runtime.
if seed_runtime && let Some(seed) = flavor::js_runtime_seed_dir() {
flavor::link_dir(&seed, &vp_home.join(flavor::JS_RUNTIME_DIR));
Expand Down Expand Up @@ -654,6 +668,7 @@ impl CaseHome {
env.insert("VP_CLI_TEST".into(), "1".into());
env.insert("NODE_NO_WARNINGS".into(), "1".into());
env.insert("VP_HOME".into(), self.vp_home().into_os_string());
env.insert("XDG_CONFIG_HOME".into(), self.xdg_config_home().into_os_string());
if cfg!(windows) {
env.insert("USERPROFILE".into(), self.home.clone().into_os_string());
env.insert(
Expand Down Expand Up @@ -688,6 +703,13 @@ impl CaseHome {
self.home.join(flavor::VP_HOME_DIR)
}

/// Case-scoped config root. pnpm resolves its global config through
/// `XDG_CONFIG_HOME` rather than `HOME`, so this must be exported
/// explicitly for the pinned `minimumReleaseAge` to apply.
fn xdg_config_home(&self) -> PathBuf {
self.home.join(".config")
}

fn npm_prefix(&self) -> PathBuf {
self.home.parent().unwrap().join("npm-global")
}
Expand Down
6 changes: 3 additions & 3 deletions docs/guide/migrate.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ You need to add overrides to your package manager so that other packages resolve
```json
"overrides": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand All @@ -94,15 +94,15 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`:
```yaml
overrides:
vite: npm:@voidzero-dev/vite-plus-core@latest
vitest: 4.1.10
vitest: 4.1.11
```

Or, if you are using Yarn:

```json
"resolutions": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand Down
6 changes: 3 additions & 3 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ Add package-manager overrides so that other packages use the Vite+ versions. Ali
```json
"overrides": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand All @@ -210,15 +210,15 @@ If you are using `pnpm`, add this to your `pnpm-workspace.yaml`:
```yaml
overrides:
vite: npm:@voidzero-dev/vite-plus-core@latest
vitest: 4.1.10
vitest: 4.1.11
```

Or, if you are using Yarn:

```json
"resolutions": {
"vite": "npm:@voidzero-dev/vite-plus-core@latest",
"vitest": "4.1.10"
"vitest": "4.1.11"
}
```

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/migration/migrator/catalog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,7 +990,7 @@ function rewriteYamlCatalogAtPath(
removeYamlMapVitestEntry(catalog);
}
for (const [key, value] of Object.entries(managed)) {
// ERR_PNPM_CATALOG_IN_OVERRIDES Could not resolve a catalog in the overrides: The entry for 'vite' in catalog 'default' declares a dependency using the 'file' protocol
// ERR_PNPM_CATALOG_IN_OVERRIDES Could not resolve a catalog in the overrides: The entry for 'vite' in catalog 'default' declares a dependency using the 'file' protocol
// ignore setting catalog if value starts with 'file:'
if (value.startsWith('file:') || (!addMissing && !catalog.has(key))) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/migration/migrator/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ const NODE_VERSION_FILE_NVMRC_RE = /(node-version-file:[ \t]*)(['"]?)(\.\/)?\.nv
* Collect GitHub Actions YAML files that may carry a `node-version-file:`
* reference: top-level workflows (`.github/workflows/*.{yml,yaml}`, which GitHub
* runs only when flat in that directory) and composite action definitions
* (`.github/actions/**/action.{yml,yaml}`, which may nest at any depth). Returns
* (`.github/actions/**\/action.{yml,yaml}`, which may nest at any depth). Returns
* absolute paths; a missing `.github` tree just yields an empty list. `nocase`
* keeps the match case-insensitive on case-sensitive filesystems.
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/utils/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const VITE_CONFIG_FILES = [
'vite.config.cts',
] as const;

export const VITEST_VERSION = '4.1.10';
export const VITEST_VERSION = '4.1.11';

export const VITE_PLUS_OVERRIDE_PACKAGES: Record<string, string> = process.env.VP_OVERRIDE_PACKAGES
? JSON.parse(process.env.VP_OVERRIDE_PACKAGES)
Expand Down
55 changes: 45 additions & 10 deletions packages/core/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -498,11 +498,42 @@ async function bundleTsdown() {
await copyFile(join(tsdownSourceDir, 'client.d.ts'), join(projectDir, 'dist/tsdown/client.d.ts'));
}

// Ensure a bundled chunk imports the given ansis color helpers (e.g. `bold`,
// `red`) from the shared `main-*.js` chunk. tsdown's logger module does not
// import every color the Vite+ branding uses, so after the logger patches we
// add any missing ones, resolving their (minified) export aliases from main's
// own `export { ... }` map so the fix survives rolldown renaming them.
// Collect the module-scope binding names a chunk declares itself, so we can tell
// whether an identifier is already in scope without importing it. Depending on
// rolldown's chunking, ansis is either kept in a shared chunk (imported) or
// inlined into this chunk as a top-level
// `const { ..., bold, red, ... } = __toESM(...)` destructuring of its CJS
// namespace, which binds the colors locally.
function collectModuleScopeBindings(source: string): Set<string> {
const bound = new Set<string>();

// Destructuring declarations: `const { a, b: c, d = 1 } = ...`.
for (const [, pattern] of source.matchAll(/^(?:const|let|var)\s*\{([^{}]*)\}\s*=/gm)) {
for (const part of pattern.split(',')) {
// `a: b` binds `b`, `a = 1` binds `a`, plain `a` binds `a`.
const colon = part.indexOf(':');
const name = (colon === -1 ? part : part.slice(colon + 1)).split('=')[0].trim();
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name)) {
bound.add(name);
}
}
}

// Simple declarations: `const a = ...`, `function a() {}`, `class a {}`.
for (const [, name] of source.matchAll(
/^(?:const|let|var|function\*?|class)\s+([A-Za-z_$][A-Za-z0-9_$]*)\b/gm,
)) {
bound.add(name);
}

return bound;
}

// Ensure the given ansis color helpers (e.g. `bold`, `red`) are in scope in a
// bundled chunk. tsdown's logger module does not reference every color the Vite+
// branding uses, so after the logger patches we add any missing ones, resolving
// their (minified) export aliases from the re-exporting chunk's own
// `export { ... }` map so the fix survives rolldown renaming them.
async function ensureAnsisImports(
content: string,
names: string[],
Expand All @@ -515,12 +546,10 @@ async function ensureAnsisImports(
// chunk actually re-exports it.
const importRe = /import \{([^}]*)\} from "(\.\/[^"]+\.js)";/g;
const imports = [...content.matchAll(importRe)];
if (imports.length === 0) {
throw new Error('ensureAnsisImports: no relative chunk import found in branded logger chunk');
}

// Every binding already in scope across all imports (its local name).
const localNames = new Set<string>();
// Every binding already in scope: the chunk's own module-scope declarations
// plus the local names of all its imports.
const localNames = collectModuleScopeBindings(content);
for (const [, bindings] of imports) {
for (const binding of bindings.split(',')) {
const trimmed = binding.trim();
Expand All @@ -533,9 +562,15 @@ async function ensureAnsisImports(
}
const missing = names.filter((name) => !localNames.has(name));
if (missing.length === 0) {
// Nothing to add — rolldown inlined the colors into this chunk (or the
// logger module already imported them).
return content;
}

if (imports.length === 0) {
throw new Error('ensureAnsisImports: no relative chunk import found in branded logger chunk');
}

// Group missing colors by the imported chunk that re-exports them. Chunks
// re-export colors as `<local> as <alias>` (e.g. `bold as i`); the consumer
// side imports `<alias> as <local>`, so capture the alias here.
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@
"@oxc-node/cli": "catalog:",
"@tsdown/css": "catalog:",
"@tsdown/exe": "catalog:",
"@vitejs/devtools": "^0.4.12",
"@vitejs/devtools": "^0.5.0-beta.1",
"es-module-lexer": "^1.7.0",
"hookable": "^6.0.1",
"magic-string": "^0.30.21",
Expand Down
Loading
Loading