- Typescript has been updated to 5.0. This means you now have to export your common tsconfig files from
package.json
in case you want to extend other configurations elsewhere in your repository.
// package.json (@repo/config)
{
"name": "@repo/config",
"exports": {
"./typescript/*.json": "./typescript/*.json"
}
}
// tsconfig.json (@repo/server)
{
"extends": "@repo/config/typescript/tsconfig.node.json",
}
❗ If you are using a version of VSCode that ships with TypeScript <5.0.3, you need to change the version of TypeScript VSCode uses to 5.0.3 or higher, which fixes this bug. This monorepo currently comes with 5.0.4 so you can use that version instead.
The easiest way to take care of this problem is by creating a .vscode
directory in the project root, and then add the following configuration to settings.json
:
{
"typescript.tsdk": "node_modules/typescript/lib",
}
or open the command palette (ctrl+shift+p) and choose > "Typescript: Select typescript version" > "Use workspace version (5.0.4)".
- Added TailwindCSS to the React package
- The way of exporting/sharing packages has changed. Check the updated section.
- Added support for React with an example app in
apps/react
.
This is an example monorepository using ESBuild for it's near-instantaneous build times and Turborepo for it's caching capabilities. It's pre-configured for TypeScript (2 different configurations for browser and for node) and ESLint for linting.
Additionally it's using NPM Workspaces, most examples I could find online were using YARN.
git clone https://github.com/barca-reddit/typescript-vscode-esbuild.git
cd typescript-vscode-esbuild
npm run watch
NB: I don't know if this is the best or the accepted way to do this, neither I consider myself an expert, so PR/issues/feedback of any kind is welcome.
Previously we were making use of typeVersions
in package.json
to share code within the monorepository, but that caused some issues. Now, we're making use of "moduleResolution": "NodeNext"
in tsconfig.json
, so that makes things easier.
To create a shared package and import it somewhere else in your monorepo, edit the contents of package.json
of the package you want to export and add the following fields:
"exports": {
".": {
"types": "./src/main.ts",
"import": "./out/main.js"
}
}
The first part of the export
object is the path you want to import (details below).
The types
key should point out to an index file where all your exports live. For example:
// src/main.ts
export const foo = "foo";
export const bar = "foo";
The import
key should point out to an index (main) file in your compiled out
directory and it's there to server plain javascript imports.
All of this allows you to do the following:
// inside some other package
import { foo, bar } from "@repo/shared";
Don't forget to add the package you're exporting as a dependency to the package you're importing it to:
// package.json
{
// ...
"dependencies": { "@repo/shared": "*" }
}
You can also have multiple import paths.
"exports": {
".": {
"types": "./src/main.ts",
"import": "./out/main.js"
},
"./server": {
"types": "./src/server/index.ts",
"import": "./out/server/index.js"
},
"./web": {
"types": "./src/web/index.ts",
"import": "./out/web/index.js"
}
}
// inside some other package
import { foo } from "@repo/shared/server";
import { bar } from "@repo/shared/web";
It is also possible to have wildcard exports like this:
"exports": {
"./*": {
"types": "./src/*.ts",
"import": "./out/*.js"
}
}
But unfortunately TypeScript is unable to find type declarations this way. If you have a solution or tips about this, issues and PRs are welcome!
For Turborepo caching to work, it's essential that all .cache
directories it creates are git-ignored.
If build order isn't important for your setup, add the --parallel
flag to the npm build
script to speed up compiling. You can probably get away with this if you don't bundle any code via bundle: true
setting passed to esbuild.
The TypeScript compiler is used only for type checking, everything else is handled by ESBuild.
TypeScript and ESLint configurations are matter of personal preference and can easily be adjusted to one's requirements. The same applies for ESBuild, you can also pass additional parameters to buildBrowser
or buildNode
which will override the default ones.
If the .cache
directories become annoying, you can just hide them in VSCode, create/edit this file under .vscode/settings.json
.
{
"files.exclude": {
"cache/": true,
"**/.turbo": true
}
}
You can quickly check whether your package dependencies are in sync, e.g, @repo/a
and @repo/b
are different versions of the same library.
// package.json (repo a)
{
"name": "repo/a",
"dependencies": {
"foo": "^1.0.0"
}
}
// package.json (repo b)
{
"name": "repo/b",
"dependencies": {
"foo": "^2.0.0"
}
}
npm run mismatch
Error: Found version mismatch for the following package:
foo - versions: ^1.0.0, ^2.0.0
- apps/package-a/package.json (@repo/a) - ^1.0.0
- apps/package-b/package.json (@repo/b) - ^2.0.0
This is just a quick and dirty solution that will only report mismatches but won't fix them for you. For more advanced solutions, check out syncpack.