30
Mono-repository with typescript and yarn workspaces
Monoliths have their place in many systems. Usually, they stem from the ease of use, allowing cross-cutting changes to be completed in a single pull request. They also have a lot of downsides, but that’s a whole other can of worms.
Here are the main points we had trouble with in our monolith:
This was an example of my repository structure:
projectA/
projectB/
projectC/
packages/
Inside my packages/ directory, I had some core shared libraries, like types / shared utils, etc.
Ok — so how do you get it all to work together?
Since we were already using yarn, it seemed like yarn workspaces would be an ideal fit. If I can get the same thing done with the same tools that's a big win.
{
"compilerOptions": {
"noImplicitAny": true,
},
"exclude": [
"**/node_modules",
"**/.*/",
"**/jest.config.js",
"**/.build"
],
}
{
...
"private": true,
"workspaces": {
"packages": [
"packages/*",
"projectA",
"projectB",
"projectC",
]
},
}
{
"name": "@company/projectA",
...
"scripts": {
"watch": "tsc -b -w --preserveWatchOutput",
...
},
"dependancies": {
"@company/types",
"@company/logging",
"@company/clients"
}
}
Now run yarn install at the root, and then at each package.
Now is a very important part. You need to add a tsconfig.json file for each of the projects. This is to assist typescript with the dependency tree. Below is an example of projectA as it depends on 3 packages — clients, types, and logging. This tells typescript to recompile if it senses any changes in the parent package.
{
"extends": "../tsconfig",
"compilerOptions": {
"outDir": ".build"
},
"rootDir": ".",
"references": [
{
"path": "../packages/clients"
},
{
"path": "../packages/types"
},
{
"path": "../packages/logging"
},
],
}
Now while running in the context of projectA you will be able to make changes to the packages it depends on e.g. /packages/types and it will recompile and display errors if there are any, along with being able to change things in projectA as normal.
30