Skip to content

tsconfig.scripts.json claims to match apps/console/tsconfig.node.json's option set but omits allowImportingTsExtensions — the shared vite-*.ts files are green in one program, red in the other #4926

Description

@yinlianghui

Observation-class finding, dormant today. Filed while implementing objectui#4854; not fixed there (out of scope, and the PR routed around it instead).

The claim, and where it stops holding

tsconfig.scripts.json's header states the invariant explicitly:

Two of the files here (scripts/vite-crypto-stub.ts, scripts/vite-maplibre-worker.ts) ARE already compiled, by apps/console/tsconfig.node.json … They are deliberately NOT excluded below … The cost of the overlap is paid by matching that project's option set (strict, ESNext, bundler resolution, and notably NO noImplicitReturns), so a shared file cannot be green in one project and red in the other.

The option sets do not in fact match. apps/console/tsconfig.node.json:30 sets "allowImportingTsExtensions": true (its header explains why: the console's config imports carry real .ts extensions so Vite's configLoader: 'native' can load them — objectui#3384). tsconfig.scripts.json sets no such option, and its compilerOptions are spelled out rather than inherited, so nothing supplies it.

Measured

tsconfig.scripts.json sets "noEmit": true, so allowImportingTsExtensions is legal there; it is simply absent. The divergence is invisible today only because no .ts file under scripts/ currently writes a specifier ending in .ts — the two named shared files import nothing relative, and scripts/__tests__/*.ts spell their imports extensionless.

It surfaces the moment anything under scripts/ reaches the console's build config. Adding a test there that statically imported apps/console/vite.config.ts produced, from pnpm type-check:scripts:

apps/console/vite.config.ts(16,32): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.
apps/console/vite.config.ts(17,36): error TS5097: An import path can only end with a '.ts' extension when 'allowImportingTsExtensions' is enabled.

Lines 16 and 17 are the pre-existing imports of scripts/vite-crypto-stub.ts and scripts/vite-maplibre-worker.ts — the exact two files the header names as deliberately shared, red in one program while tsc -b apps/console/tsconfig.node.json --force stays green on the same bytes. That is the shape the header says the matched option set prevents.

Why it is filed rather than fixed

PR for objectui#4854 needed to evaluate the console's config from a scripts/__tests__ test. It assembles the specifier at runtime instead, which keeps apps/console/vite.config.ts out of the scripts program entirely — the program boundary the header is really defending. Widening a shared tsconfig as a rider on a build-hook PR is the wrong place for the decision, so it is left here.

Two options for whoever picks it up, neither obviously free:

  1. Add "allowImportingTsExtensions": true to tsconfig.scripts.json, restoring the stated invariant. Cheap, and it makes the header true again.
  2. Decide the invariant is narrower than written — the option is a property of how the console loads its config, not of the shared files — and correct the header instead, naming allowImportingTsExtensions as a deliberate difference with its reason.

Either way, scripts/__tests__/scripts-type-check.test.ts is where the choice should be pinned; it already asserts noEmit/strict/composite on this project and would be the natural home for an option-parity assertion against apps/console/tsconfig.node.json, which is what would have caught this.

Nothing a user hits, nothing red on main — hence finding and no pm:queue.

Metadata

Metadata

Labels

domain:devxobjectui devx stream: fix lands on .github/, scripts/ or release pipeline — devx lane cross-repopm:dispatched

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions