Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/composite monorepo #8560

Open
wants to merge 35 commits into
base: main
Choose a base branch
from
Open

Feature/composite monorepo #8560

wants to merge 35 commits into from

Conversation

TkDodo
Copy link
Collaborator

@TkDodo TkDodo commented Jan 21, 2025

This PR changes the structure of our monorepo towards a composite typescript setup.

In a composite monorepo, each package can be built in isolation with TSC to provide types other packages can consume. This has the following advantages and fixes the following issues:

Code Navigation

Clicking on an import in your IDE that imports something from a dependent package, like:

import { QueryObserver } from '@tanstack/query-core'

in a framework adapter used to take you to the .d.ts file in the build directory. Now, it takes you directly to the source.

Changes are picked up immediately

Because packages are linked together by sources via typescript path aliases, a change in query-core will automatically highlight all errors in your editor in adapter files. Previously, a build was needed, and oftentimes also a restart of the ts language server in your editor.

Tests

Tests also know about typescript path aliases thanks to the vite-tsconfig-paths package (and dynamic path aliases, which are necessary to override what we have in package.json as main/exports entries). That means we can add a log statement to a query-core file and execute a test in a framework adapter without an in-between build step.

No build dependency

All tasks like linting and type checking no longer need a build of dependent packages - they do need a compile task though that instructs typescript to build the output.

Things changed

New compile task

(Mainly) to make CI work, we have a new compile task that will instruct tsc to build all packages. For this, I had to switch svelte packages towards "moduleResolution": "Bundler". I hope this doesn’t break anything @lachlancollins

Isolated packages

Packages need to be isolated, so the rootDir was always set to ”.”. However, we have imported things from ../../, like the global eslint config. To work around this, I’ve created symlinks within the rootDir of all packages, because those imports were no longer allowed.

References

Each package must define its own dependencies as references in tsconfig.json. Those reference point towards other packages, so that typescript can know about the build graph. This has to be kept in-sync with workspace dependencies in package.json

Path mappings

TypeScript path mappings are defined in the root tsconfig json. All packages must be listed there - this is also what we use to build aliases for the vite configs.

Copy link

pkg-pr-new bot commented Jan 25, 2025

Open in Stackblitz

More templates

@tanstack/angular-query-devtools-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-devtools-experimental@8560

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@8560

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@8560

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@8560

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@8560

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@8560

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@8560

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@8560

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@8560

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@8560

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@8560

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@8560

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@8560

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@8560

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@8560

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@8560

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@8560

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@8560

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@8560

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@8560

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@8560

commit: 14f24df

Copy link

github-actions bot commented Jan 25, 2025

Sizes for commit 14f24df:

Branch Bundle Size
Main
This PR

Copy link

codecov bot commented Jan 26, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 46.28%. Comparing base (d595e23) to head (14f24df).

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #8560   +/-   ##
=======================================
  Coverage   46.28%   46.28%           
=======================================
  Files         199      199           
  Lines        7538     7538           
  Branches     1721     1724    +3     
=======================================
  Hits         3489     3489           
  Misses       3670     3670           
  Partials      379      379           
Components Coverage Δ
@tanstack/angular-query-devtools-experimental ∅ <ø> (∅)
@tanstack/angular-query-experimental 88.65% <ø> (ø)
@tanstack/eslint-plugin-query 88.22% <ø> (ø)
@tanstack/query-async-storage-persister 43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental ∅ <ø> (∅)
@tanstack/query-codemods 0.00% <ø> (ø)
@tanstack/query-core 94.15% <ø> (ø)
@tanstack/query-devtools 4.78% <ø> (ø)
@tanstack/query-persist-client-core 57.73% <ø> (ø)
@tanstack/query-sync-storage-persister 84.61% <ø> (ø)
@tanstack/react-query 95.94% <ø> (ø)
@tanstack/react-query-devtools 10.00% <ø> (ø)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client 100.00% <ø> (ø)
@tanstack/solid-query 78.20% <ø> (ø)
@tanstack/solid-query-devtools ∅ <ø> (∅)
@tanstack/solid-query-persist-client 100.00% <ø> (ø)
@tanstack/svelte-query 87.33% <ø> (ø)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client 100.00% <ø> (ø)
@tanstack/vue-query 71.01% <ø> (ø)
@tanstack/vue-query-devtools ∅ <ø> (∅)

@TkDodo TkDodo marked this pull request as ready for review January 26, 2025 18:25
@jakebailey
Copy link

Drive by review (I saw this on bluesky):

Packages need to be isolated, so the rootDir was always set to ”.”. However, we have imported things from ../../, like the global eslint config. To work around this, I’ve created symlinks within the rootDir of all packages, because those imports were no longer allowed.

In a composite build rootDir is defaulted to the config dir, so you probably don't need that. For the other files, have you considered using a separate config for those files instead and not including them in the build for any package? (Or honestly, not even including them at all?)

Speaking of referencing from the root, I would suggest not putting anything in the config at the very root of the repo, instead making that a "solution" tsconfig whose only role it is to help tsserver find other configs (or to do a big tsc -b). An example of this is https://github.com/microsoft/TypeScript/blob/main/src/tsconfig.json or https://github.com/microsoft/DefinitelyTyped-tools/blob/main/tsconfig.json. Then, a separate base for each thing to inherit from.

typescript-eslint/typescript-eslint#10361 is also something you might want to look at, since it's also a project moving to this layout and also using nx (which I believe is currently undergoing a refactor to be able to generate the exact thing you want).

Tests also know about typescript path aliases thanks to the vite-tsconfig-paths package (and dynamic path aliases, which are necessary to override what we have in package.json as main/exports entries).

I'm surprised you need path aliases at all; in a monorepo those are usually very well covered by the package manager doing symlinking and then imports "just work". Path aliases are (IMO) best avoided beacuse they entirely bypass any and all module resolution logic (which may hide issues).

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