voidzero-dev / voidzero-dev/vite-plus

Remove `"include": ["src"]` from `tsconfig.json` in `vp create vite:library` template

Open
#1,308 0 comments 0 reactions 1 assignee Claimed by @fengmk2 View on GitHub
pending triage
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

Image

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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.