voidzero-dev / voidzero-dev/vite-plus
Remove `"include": ["src"]` from `tsconfig.json` in `vp create vite:library` template
- Dominant language
- Rust
- Stars
- 5.8k
- Forks
- 262
- Avg merge
- 1d 34m
- Merged PRs (30d)
- 135
Description
### Description
Projects generated by `vp create vite:library` include a `tsconfig.json` like the following:
```json
{
"compilerOptions": {
"target": "esnext",
"lib": ["es2023"],
"moduleDetection": "force",
"module": "nodenext",
"moduleResolution": "nodenext",
"resolveJsonModule": true,
"types": ["node"],
"strict": true,
"noUnusedLocals": true,
"declaration": true,
"noEmit": true,
"allowImportingTsExtensions": true,
"esModuleInterop": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
},
"include": ["src"]
}
```
The key issue is that the `include` field is limited to the `src` directory only. This causes the following problems.
### Problem 1: Cannot auto-import items from `src` directory files outside of `src`
Files outside of the `src` directory cannot auto-import functions and other items from the `src` directory. For example, files in the `tests` directory cannot auto-import functions defined in `src`.
Steps to reproduce:
1. `git clone https://github.com/mizdra-sandbox/repro-vp-lib-tsconfig-is-missing`
2. `cd repro-vp-lib-tsconfig-is-missing`
3. `code --profile-temp .` (using VS Code)
4. Open `tests/index.test.ts`
5. Place the cursor after `fn` and trigger completion
- Expected behavior: `fn` should be suggested
- Actual behavior: `fn` is not suggested
tsserver treats files in the `src` directory as part of the `tsconfig.json` project, but treats files in the `tests` directory as part of an "Inferred Project". An Inferred Project is one that tsserver automatically assigns to files that have no corresponding `tsconfig.json`. Since tsserver cannot auto-import items between files belonging to different projects, files in `tests` cannot auto-import items from files in `src`.
### Problem 2: Expected compiler options are not applied to files outside `src`
The `tsconfig.json` includes `"noUnusedLocals": true`. While the `src` directory is affected by this option, the `tests` directory, `vite.config.ts`, and similar files are not. As a result, unused local variables in those files are not reported as errors.
Steps to reproduce:
1. `git clone https://github.com/mizdra-sandbox/repro-vp-lib-tsconfig-is-missing`
2. `cd repro-vp-lib-tsconfig-is-missing`
3. `code --profile-temp .` (using VS Code)
4. Open `tests/index.test.ts`
5. Add code containing an unused local variable (e.g. `const unused = 1;`)
6. Run `vp check`
```console
$ vp check
VITE+ - The Unified Toolchain for the Web
pass: All 7 files are correctly formatted (158ms, 14 threads)
error: Lint or type issues found
× typescript(TS2304): Cannot find name 'fn'.
╭─[tests/index.test.ts:3:1]
2 │ const unused = 1;
3 │ fn();
· ──
╰────
Found 1 error and 0 warnings in 3 files (140ms, 14 threads)
```
- No `noUnusedLocals` error is reported for `const unused = 1;`
- Expected behavior: if `noUnusedLocals` were applied, an "unused variable" error for `unused` should be reported in addition to the "cannot find name" error for `fn`
Users would reasonably expect the same compiler options applied to `src` to also apply to files in `tests`, `vite.config.ts`, and similar locations. This behavior is therefore likely to cause confusion.
### Suggested solution
Remove the `"include"` field from `tsconfig.json` in projects generated by `vp create vite:library`. Omitting `"include"` is equivalent to specifying `"include": ["**/*"]`, which causes all TypeScript files to be treated as part of the `tsconfig.json` project. This resolves both problems described above.
### Alternative
None.
### Additional context
### About projects generated by `vp create vite:application`
The `tsconfig.json` in projects generated by `vp create vite:application` also contains `"include": ["src"]`, so the same problems occur. The `"include"` field should be removed there as well to broaden the scope.
### Compiler options used by Inferred Projects
Files in `tests`, `vite.config.ts`, and similar locations belong to an Inferred Project, so Inferred Project settings are applied to them. In tsserver, the options used are either the values sent by the editor via a `setCompilerOptionsForInferredProjects` request, or the default values defined in TypeScript's `src/server/project.ts`.
- https://github.com/microsoft/vscode/blob/8d415912364f9b29d76ae6bfc59234e59e03dbc7/extensions/typescript-language-features/src/typescriptServiceClient.ts#L622-L630, https://github.com/microsoft/vscode/blob/8d415912364f9b29d76ae6bfc59234e59e03dbc7/extensions/typescript-language-features/src/tsconfig.ts#L23
- (when tsserver version >= 5.4.0) `"module": "Preserve"`, `"moduleResolution": "Bundler"`, `"target": "ES2022"`, `"allowImportingTsExtensions": true`, ...
- (when tsserver version < 5.4.0) `"module": "ESNext"`, `"moduleResolution": "Bundler"`, `"target": "ES2022"`, `"allowImportingTsExtensions": true`, ...
- https://github.com/microsoft/TypeScript/blob/7b8cb3bdf82f400642b73173f941335775d6f730/src/server/project.ts#L590-L594, https://github.com/microsoft/TypeScript/blob/7b8cb3bdf82f400642b73173f941335775d6f730/src/services/services.ts#L1384
- `"module": "ESNext"`, `"moduleResolution": "Bundler"`, `"target": "ESNext"`, `"allowImportingTsExtensions": false`, ...
In oxlint, the values defined in the `CreateInferredProjectProgram` function are used.
- https://github.com/oxc-project/tsgolint/blob/757a9968aeb3ab543515738d1a26aa95176b84ee/internal/utils/create_program.go#L124-L139
- `"module": "ESNext"`, `"moduleResolution": "Bundler"`, `"target": "ES2022"`, `"allowImportingTsExtensions": true`, ...
### Side effects of broadening the scope of `tsconfig.json`
Broadening the scope of `tsconfig.json` has some side effects.
#### Side effect 1: `"module": "nodenext"` and `"moduleResolution": "nodenext"` are applied to files outside `src`
The compiler options intended for `src` will also be applied to files in other directories. Of particular note are `"module": "nodenext"` and `"moduleResolution": "nodenext"`. It is worth considering whether applying these to the `tests` directory, config files (e.g. `vite.config.ts`), and a `scripts` directory (e.g. https://github.com/vitest-dev/vitest/tree/main/scripts) is acceptable.
In my view, applying these options to `tests` and config files should not be a problem. The `src` directory is built by `vp pack` and `tests` is run by `vp test`; both are backed by Vite, which supports building code that assumes `"module": "nodenext"` and `"moduleResolution": "nodenext"`.
Applying these options to config files should also be fine. Config files are either executed via Node.js Type Stripping (e.g. `prettier.config.ts`) or bundled before execution (e.g. `vite.config.ts`), and both execution models support code that assumes these module settings. The same applies to a `scripts` directory.
Therefore, this side effect is not a significant concern.
#### Side effect 2: Per-directory compiler options become harder to configure
In some cases, users may want to apply different compiler options per directory. For example, they may want `"allowImportingTsExtensions": true` for `src` and `tests`, but not for `scripts`.
If that is needed, a "solution-style" `tsconfig.json` can be added later to achieve per-directory configuration.
- https://www.typescriptlang.org/docs/handbook/project-references.html#overall-structure
- https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-9.html#support-for-solution-style-tsconfigjson-files
```json
// tsconfig.json
{
"files": [],
"references": [
{ "path": "./tsconfig.default.json" }, // For `src` and `tests` directories
{ "path": "./tsconfig.scripts.json" } // For `scripts` directory
]
}
```
```json
// tsconfig.default.json
{
"compilerOptions": {
"target": "esnext",
"lib": ["es2023"],
"moduleDetection": "force",
"module": "nodenext",
"moduleResolution": "nodenext",
"allowImportingTsExtensions": true
// ...
}
}
```
```json
// tsconfig.scripts.json
{
"compilerOptions": {
"target": "esnext",
"lib": ["es2023"],
"moduleDetection": "force",
"module": "nodenext",
"moduleResolution": "nodenext"
// "allowImportingTsExtensions": true,
// ...
}
}
```
Since a workaround exists, this side effect is not a significant concern.
### Validations
- [x] Read the [Contributing Guidelines](https://github.com/voidzero-dev/vite-plus/blob/main/CONTRIBUTING.md).
- [x] Confirm this request is for Vite+ itself and not for Vite, Vitest, tsdown, Rolldown, or Oxc.
- [x] Check that there isn't already an issue requesting the same feature.
Contributor guide
Assessment
This issue has not been assessed yet.