Skip to content

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

@mizdra

Description

@mizdra

Description

Projects generated by vp create vite:library include a tsconfig.json like the following:

{
  "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
    $ 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.

In oxlint, the values defined in the CreateInferredProjectProgram function are used.

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.

// tsconfig.json
{
  "files": [],
  "references": [
    { "path": "./tsconfig.default.json" }, // For `src` and `tests` directories
    { "path": "./tsconfig.scripts.json" } // For `scripts` directory
  ]
}
// tsconfig.default.json
{
  "compilerOptions": {
    "target": "esnext",
    "lib": ["es2023"],
    "moduleDetection": "force",
    "module": "nodenext",
    "moduleResolution": "nodenext",
    "allowImportingTsExtensions": true
    // ...
  }
}
// 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

  • Read the Contributing Guidelines.
  • Confirm this request is for Vite+ itself and not for Vite, Vitest, tsdown, Rolldown, or Oxc.
  • Check that there isn't already an issue requesting the same feature.

Metadata

Metadata

Assignees

No one assigned

    Priority

    None yet

    Start date

    None yet

    Target date

    None yet

    Effort

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions