Skip to content

barca-reddit/esbuild-typescript-turborepo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESBuild TypeScript Turborepo Monorepo starter/example

Update April 2023:

  • 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)".

Update February 2023:

  • Added TailwindCSS to the React package

Update December 2022:

  • The way of exporting/sharing packages has changed. Check the updated section.

Update November 2022:

  • Added support for React with an example app in apps/react.

Details:

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.

Installation:

git clone https://github.com/barca-reddit/typescript-vscode-esbuild.git

cd typescript-vscode-esbuild

npm run watch

Tech stack:

Exporting/sharing packages:

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!

Notes:

Turborepo

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.

TSC

The TypeScript compiler is used only for type checking, everything else is handled by ESBuild.

Typescript/Eslint

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.

VSCode

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
    }
}

Version mismatches

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.

Useful resources: