Skip to content

[No QA] Consolidate TypeScript projects under a root project with subproject references - #100553

Merged
roryabraham merged 2 commits into
mainfrom
rory/tsconfig-project-references
Sep 8, 2026
Merged

roryabraham merged 2 commits into
mainfrom
rory/tsconfig-project-references

Conversation

@roryabraham

@roryabraham roryabraham commented Sep 7, 2026 •

Copy link
Copy Markdown
Contributor

Explanation of Change

Consolidate the per-runtime TypeScript projects under the root tsconfig.json using Project References.

The bug this fixes

Splitting the Jest project out of the root config in #100124 removed tests, jest and __mocks__ from the root tsconfig.json's include. A language service resolves a file to the closest tsconfig.json, so those files still landed on the root config, did not appear in it, and fell back to an inferred project — which has no paths. That is why @libs stopped resolving in tests/.

Reproduced by driving tsserver directly, before and after. The fix is a root project that owns no files, only project references. So the language service walks references to the project that does own the file, and type-checks it with that project's options.

Changes

  • npm run typecheck takes its project list from those references. It still runs each project in parallel for performance (tsc by default is sequential).
  • Drops the dead includes phase 3 asked for but did not land: website (does not exist), docs (already excluded), .claude (was pulling two unrelated .mjs files into the app program), **/*.nitro/* (already covered by modules).
  • Lists the files the app import graph already reached but the config did not admit to: wdyr.ts (from src/App.tsx), config/proxyConfig.ts (from src/libs/ApiUtils.ts), config/rsbuild (from .storybook), __mocks__/reportData (from the Storybook stories).
  • Moves prompts out of the app and Jest programs into the Bun program. Nothing in src/ imports it; scripts/, evals/ and tests/tooling/ do.
  • Each project names its own tsBuildInfoFile. modules/ExpensifyNitroUtils now extends tsconfig.app.json and sets its own, so it cannot clobber the app's.

Timings

before after
cold 34.8s / 46.7s 41.5s / 47.3s
warm 4.5s / 4.1s 1.16s / 1.13s

Cold is a wash; warm is ~4× faster because build mode skips a project whose build info is current instead of rebuilding its program.

Fixed Issues

$ #99291
PROPOSAL: N/A

Tests

Automated tests / CI only.

  • Verify that no errors appear in the JS console (not applicable: tooling-only change)

Offline tests

Not applicable: tooling-only change.

QA Steps

n/a - tooling-only change.

  • Verify that no errors appear in the JS console (not applicable: tooling-only change)

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (not applicable: tooling-only change)
    • I turned off my network connection and tested it while offline (not applicable: tooling-only change)
    • I tested this PR with a High Traffic account (not applicable: tooling-only change)
  • I included screenshots or videos for tests on all platforms (not applicable: tooling-only change)
  • I ran the tests on all platforms & verified they passed on (not applicable: tooling-only change):
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (not applicable: tooling-only change)
  • I followed proper code patterns
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained why
    • I verified any copy/text added to the app is grammatically correct (not applicable)
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the Review Guidelines
  • I tested other components that can be impacted by my changes (not applicable)
  • If a new CSS style is added I verified it (not applicable)
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function
  • If new assets were added or existing ones were modified (not applicable)
    • The assets are optimized and compressed
    • The assets load correctly across all supported platforms
  • If the PR modifies code that runs when editing or sending messages, I tested markdown behavior (not applicable)
  • If the PR modifies a generic component, I tested impacted usages (not applicable)
  • If the PR modifies a component related to Storybook stories, I verified stories (not applicable)
  • If the PR modifies a page accessible by deeplink, I verified deeplinks (not applicable)
  • If the PR modifies UI or form input styles, I verified alignment and design review (not applicable)
  • I added unit tests for any new feature or bug fix (not applicable: configuration-only change)
  • If main was merged after review, I tested again (not applicable)

Screenshots/Videos

Not applicable: tooling-only change.

Make the root `tsconfig.json` a solution-style config that references every
project instead of being the app program itself.

Splitting the Jest project out of the root config (#100124) left files under
`tests/` and `jest/` outside every project, so editors resolved them to an
inferred project with no `paths` and `@libs`/`@src` stopped resolving. A
solution-style root fixes that: the language service finds this config, sees it
owns no files, and walks `references` to the project that does.

- Move the app program to `tsconfig.app.json` and leave `tsconfig.json` with
  `files: []` plus `references`.
- Point `npm run typecheck` at those references, so a project joins CI by being
  referenced and nowhere else, and run `tsc --build` for the build-mode
  up-to-date check.
- Drop the dead includes phase 3 called for: `website` (does not exist), `docs`
  (already excluded), `.claude` (was pulling in unrelated `.mjs` files) and
  `**/*.nitro/*` (already covered by `modules`).
- List the files the app import graph already reached (`wdyr.ts`,
  `config/proxyConfig.ts`, `config/rsbuild`, `__mocks__/reportData`) and move
  `prompts` to the Bun program, which is what actually consumes it.
@roryabraham

Copy link
Copy Markdown
Contributor Author

@codex review

@roryabraham

Copy link
Copy Markdown
Contributor Author

@MelvinBot review

@MelvinBot

Copy link
Copy Markdown
Contributor

⚠️ A setup step failed before I could start. This is usually a temporary issue — try again in a few minutes, and if it persists post in #melvinbot-ai.

Run details

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 793d63e366

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@roryabraham
roryabraham marked this pull request as ready for review September 7, 2026 22:30
@roryabraham
roryabraham requested a review from a team as a code owner September 7, 2026 22:30
@melvin-bot
melvin-bot Bot requested review from ikevin127 and removed request for a team September 7, 2026 22:30
@melvin-bot

melvin-bot Bot commented Sep 7, 2026

Copy link
Copy Markdown

@ikevin127 Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@roryabraham roryabraham changed the title [No QA] Consolidate TypeScript projects under a root solution [No QA] Consolidate TypeScript projects under a root project with subproject references Sep 7, 2026
@roryabraham roryabraham mentioned this pull request Sep 7, 2026
38 tasks done

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 793d63e366

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread tsconfig.json
".github",
"web/proxy.ts",
"config"
"files": [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep bare tsc from becoming a no-op

With files: [], running the deliberately installed bare npx tsc now exits successfully without checking any referenced project; I confirmed tsc -p tsconfig.json --listFiles reports no files. This contradicts scripts/postInstall.sh:34-36, which explicitly makes bare npx tsc match npm run typecheck, and can give developers a false clean result. The compiler help confirms that only --build “build[s] one or more projects and their dependencies,” while normal project mode compiles just the selected project, so references are not traversed here.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Legit, and the citation is accurate — fixed in 6884ceb.

Confirmed both halves:

  • tsc -p tsconfig.json --listFiles reports 0 files, and bare tsc -p tsconfig.json exits 0 with no output. Project mode does not follow references; only --build does.
  • scripts/postInstall.sh really did promise npx tsc "matches npm run typecheck", so that comment was stale the moment the root became a solution.

I also checked whether "include": [] would at least make it fail loudly instead of silently. It does not — same silent exit 0. So there is no config-level fix; the promise itself had to go.

What I did not do, and why: I tested keeping the app program on the root config alongside references, which would have preserved bare tsc. tsserver still solution-searches in that shape — tests/unit/ActiveSpansTest.ts still resolved to tsconfig.jest.json — so it would have worked for the IDE fix too. I went with the solution-style root anyway because that shape gives one file two jobs: scripts/typecheck.ts could no longer derive its project list from references alone (the root's own program is not in its own references), and #99495 splits the app program into web + native next, which would have to dismantle it again. Happy to revisit if you'd rather keep bare tsc meaningful.

The symlink still earns its keep — it forces TypeScript 7 over the tsc bin @typescript/old ships — so I kept it and corrected the claim around it:

# Force the TypeScript 7 native compiler, so `npx tsc` is the compiler `npm run typecheck` runs.
#
# It is not the same *command*: the root tsconfig.json is a solution that lists projects and owns no
# files, and project mode does not follow `references`. `npx tsc` at the repo root therefore checks
# nothing and exits 0. Use `npx tsc --build`, which walks the references, or `npm run typecheck`.

For what it's worth npx tsc --build with no project argument does the right thing at the root: it walks all five references, and I verified it exits 1 on a planted error. Nothing in the repo invokes bare tsc (only scripts/typecheck.ts, by explicit path, with --build), and CLAUDE.md:72 already points at npm run typecheck, so the exposure was a human at a terminal — which is exactly the case the comment now covers.

The root config is a solution now, and project mode does not follow
`references`, so `npx tsc` at the repo root checks nothing and exits 0.
The symlink still matters (it forces TypeScript 7 over the `tsc` bin that
`@typescript/old` ships), but it no longer makes bare `tsc` equivalent to
`npm run typecheck`. Point at `tsc --build` instead.
Comment thread tsconfig.app.json
Comment on lines +14 to +17
// Not app directories, but the app program reaches into them: `src/App.tsx` imports
// `wdyr`, `src/libs/ApiUtils` imports `config/proxyConfig`, `.storybook` imports the
// Rsbuild config, and the Storybook stories import the shared report fixtures. They were
// already being type-checked here via those imports; listing them makes that visible.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NAB: this appears red since comments aren't valid in JSON. Not sure if it matters of if there's a workaround.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tsconfig is jsonc (even though it doesn't have that extension). So it allows comments and trailing commas.

@roryabraham
roryabraham merged commit 746552a into main Sep 8, 2026
36 of 38 checks passed
@roryabraham
roryabraham deleted the rory/tsconfig-project-references branch September 8, 2026 16:16
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🚧 roryabraham has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

OSBotify commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify OSBotify mentioned this pull request Sep 8, 2026
69 tasks done
@OSBotify

OSBotify commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/roryabraham in version: 9.4.74-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

@jponikarchuk

Copy link
Copy Markdown

Deploy Blocker #100698 was identified to be related to this PR.

@jponikarchuk jponikarchuk mentioned this pull request Sep 9, 2026
1 of 4 tasks
@OSBotify

OSBotify commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/mountiny in version: 9.4.74-2 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants