Skip to content

Commit f1547b7

Browse files
committed
docs(guide): document vite.config.ts nested-config resolution
Adds a dedicated Nested Configuration guide covering how `vp lint` and `vp fmt` select a `vite.config.ts`, with an explicit note on the asymmetry between the two: `vp lint` is cwd-only, while `vp fmt` walks up until it finds a config. Cross-links it from the Lint and Format pages and the Check sidebar. Adds snap-tests/docs-nested-config to pin each documented claim (cwd walk-up for fmt, cwd-only fallback for lint, root-cwd wins over nested configs, `-c <path>` bypasses cwd resolution) so the guide stays in sync with actual behavior.
1 parent a2115d5 commit f1547b7

File tree

15 files changed

+300
-0
lines changed

15 files changed

+300
-0
lines changed

docs/.vitepress/config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const guideSidebar = [
4242
items: [
4343
{ text: 'Lint', link: '/guide/lint' },
4444
{ text: 'Format', link: '/guide/fmt' },
45+
{ text: 'Nested Configuration', link: '/guide/nested-config' },
4546
],
4647
},
4748
{ text: 'Test', link: '/guide/test' },

docs/guide/fmt.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ For editors, point the formatter config path at `./vite.config.ts` so format-on-
3030

3131
For the upstream formatter behavior and configuration reference, see the [Oxfmt docs](https://oxc.rs/docs/guide/usage/formatter.html).
3232

33+
In monorepos, `vp fmt` walks up from the current working directory and uses the first `vite.config.ts` it finds — unlike `vp lint`, which is cwd-only. See [Nested Configuration](/guide/nested-config) for the full resolution rules.
34+
3335
```ts
3436
import { defineConfig } from 'vite-plus';
3537

docs/guide/lint.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Put lint configuration directly in the `lint` block in `vite.config.ts` so all y
2222

2323
For the upstream rule set, options, and compatibility details, see the [Oxlint docs](https://oxc.rs/docs/guide/usage/linter.html).
2424

25+
In monorepos, `vp lint` uses `<cwd>/vite.config.ts` if it exists, and falls back to Oxlint's built-in defaults otherwise — it does not walk up. See [Nested Configuration](/guide/nested-config) for details.
26+
2527
```ts
2628
import { defineConfig } from 'vite-plus';
2729

docs/guide/nested-config.md

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Nested Configuration
2+
3+
Vite+ supports multiple `vite.config.ts` files in the same repository, so packages in a monorepo can have their own lint and format settings while sharing a baseline.
4+
5+
`vp lint` and `vp fmt` resolve configuration from the **current working directory** (cwd), but with one subtle difference:
6+
7+
- **`vp lint`** — cwd-only. Uses `<cwd>/vite.config.ts` if it exists. If not, falls back to Oxlint's built-in defaults — it does **not** walk up to find an ancestor config.
8+
- **`vp fmt`** — cwd walk-up. Walks up from cwd and uses the first `vite.config.ts` it finds. If none is found anywhere up to the filesystem root, falls back to Oxfmt defaults.
9+
10+
In both cases, the selected config applies to every path in the run.
11+
12+
If you only need to exclude files or folders, use [`lint.ignorePatterns`](/config/lint) or [`fmt.ignorePatterns`](/config/fmt) instead.
13+
14+
## How it works
15+
16+
Given the following structure:
17+
18+
```
19+
my-project/
20+
├── vite.config.ts
21+
├── src/
22+
│ └── index.ts
23+
├── package1/
24+
│ ├── vite.config.ts
25+
│ └── src/index.ts
26+
└── package2/
27+
└── src/index.ts
28+
```
29+
30+
`vp lint`:
31+
32+
- From `my-project/` → uses `my-project/vite.config.ts` for every file (including files under `package1/` and `package2/`).
33+
- From `my-project/package1/` → uses `my-project/package1/vite.config.ts`.
34+
- From `my-project/package2/` → no local `vite.config.ts`, so Oxlint's built-in defaults are used.
35+
- From `my-project/package1/src/` → no local `vite.config.ts`, so Oxlint's built-in defaults are used even though `package1/vite.config.ts` exists one level up.
36+
37+
`vp fmt`:
38+
39+
- From `my-project/` → uses `my-project/vite.config.ts`.
40+
- From `my-project/package1/` → uses `my-project/package1/vite.config.ts`.
41+
- From `my-project/package2/` → walks up past `package2/` and uses `my-project/vite.config.ts`.
42+
- From `my-project/package1/src/` → walks up past `src/` and uses `my-project/package1/vite.config.ts`.
43+
44+
If your monorepo needs different settings per package, run `vp lint` / `vp fmt` from each package directory (for example, via a `vp run -r lint` task), or pin a specific config with `-c`.
45+
46+
## What to expect
47+
48+
Configuration files are not automatically merged. When a file is selected, it fully replaces any other config — there is no parent/child layering. To share settings, import the parent config and spread it; see the [monorepo pattern](#monorepo-pattern-share-a-base-config) below.
49+
50+
Command-line options override configuration files.
51+
52+
Passing an explicit config file location using `-c` or `--config` bypasses cwd-based resolution entirely, and only that single configuration file is used — for both `vp lint` and `vp fmt`.
53+
54+
For lint, you can also pass `--disable-nested-config` to stop Oxlint from picking up any stray legacy config files that may exist in the tree:
55+
56+
```bash
57+
vp lint --disable-nested-config
58+
vp check --disable-nested-config
59+
```
60+
61+
There is no equivalent flag for `vp fmt`; pass `-c` if you need to pin a single format config.
62+
63+
`options.typeAware` and `options.typeCheck` are root-config-only. If either is set in a nested `vite.config.ts` that ends up being selected as the lint config, `vp lint` reports an error.
64+
65+
::: tip Breaking change since the April 2026 release
66+
67+
Earlier versions of Vite+ always injected the workspace-root `vite.config.ts` into every `vp lint` / `vp fmt` invocation, regardless of cwd. Vite+ now lets cwd-based resolution select the config, so running `vp lint` / `vp fmt` from inside a sub-package picks up that sub-package's own `vite.config.ts`. See [#1378](https://github.com/voidzero-dev/vite-plus/pull/1378) for the migration notes.
68+
69+
:::
70+
71+
## Monorepo pattern: share a base config
72+
73+
In a monorepo, you often want one shared baseline at the root and small package-specific adjustments. Import the root `vite.config.ts` from the nested one and spread it:
74+
75+
```ts [my-project/vite.config.ts]
76+
import { defineConfig } from 'vite-plus';
77+
78+
export default defineConfig({
79+
lint: {
80+
rules: {
81+
'no-debugger': 'error',
82+
},
83+
},
84+
});
85+
```
86+
87+
```ts [my-project/package1/vite.config.ts]
88+
import { defineConfig } from 'vite-plus';
89+
import baseConfig from '../vite.config.ts';
90+
91+
export default defineConfig({
92+
...baseConfig,
93+
lint: {
94+
...baseConfig.lint,
95+
rules: {
96+
...baseConfig.lint?.rules,
97+
'no-console': 'off',
98+
},
99+
},
100+
});
101+
```
102+
103+
This keeps the shared baseline in one place and makes package configs small and focused.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "docs-nested-config-test",
3+
"version": "0.0.0",
4+
"private": true,
5+
"type": "module",
6+
"packageManager": "pnpm@10.16.1"
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "pkg-a",
3+
"version": "0.0.0",
4+
"private": true
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function pkgA() {
2+
debugger;
3+
return "hello from pkg-a";
4+
}
5+
6+
export { pkgA };
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Nested config in pkg-a: relaxes the root's strict rules.
2+
// cwd walk-up from pkg-a/ should pick this file, not the root.
3+
export default {
4+
lint: {
5+
rules: {
6+
'no-debugger': 'off',
7+
},
8+
},
9+
fmt: {
10+
singleQuote: false,
11+
},
12+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "pkg-b",
3+
"version": "0.0.0",
4+
"private": true
5+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
function pkgB() {
2+
debugger;
3+
return "hello from pkg-b";
4+
}
5+
6+
export { pkgB };

0 commit comments

Comments
 (0)