Exploring the Monorepo #2: Workspaces (npm, pnpm)

Table Of Contents

Okay so attempt #1 didn't quite work, but all the package managers have a feature called Workspaces, which npm describes like this:

[Workspaces] provides support to managing multiple packages from your local files system from within a singular top-level, root package.

That sure sounds relevant, so let's give it a try!

npm

The npm documentation is so terse I've honestly no clue how to get anything working 🤷‍♀️. If you know your way around npm workspaces I'm happy to swap stories, but for now I'm giving up on this.

pnpm

Documentation here is definitely a step up, with more examples to draw inspiration from. Still a bit hard to grasp though, but I also came across this nice "actual complete guide to typescript monorepos" article by @cryogenicplanet that put some of the details together in an understandable way. Thanks Rahul!

The end-result of workspacifying the product comes out like this:

webby
├── apps
│  ├── api/
│  └── web/
├── libs
│  ├── analytics/
│  ├── logging/
│  └── types/
├── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
└── tsconfig.json

ℹ️ This project is prepared on GitHub1s if you'd like to familiarize yourself with the code.

Each app and lib's package.json is scoped to just that piece of code, so just like before we have a great immediate overview. The real question is: Does it work?

Well… apps/web runs fine:

$ cd apps/web
$ pnpm install
Scope: all 6 workspace projects
└─ Done in 3.2s
$ pnpm start
[razzle] > Started on port 3000

So just running pnpm install in apps/web actually resolved all dependencies for the whole repository, which is very nice. And all it takes to configure it are a few lines in the ppm-workspace.yaml file, so it's all very easy to get working.

But apps/api fails just as it did in the previous article:

$ cd ../api
$ pnpm start
[api] TSError: ⨯ Unable to compile TypeScript:
[api] ../../libs/analytics/src/index.ts(8,3): error TS2564: Property 'uninitializedProperty' has no initializer and is not definitely assigned in the constructor.

With help from @cryogenicplanet 's article I finally looked into Typescript Project References, which is a way to tell Typescript how to deal with multiple code pieces. But the same error occurs with or without references so I’m not sure if they’re the answer and I’ve just done it wrong or if there’s a deeper problem.

Conclusion

I'm not sure how to proceed from here. The pnpm tool itself seems to work great, what I need to figure out is how to get Typescript to use each package's own tsconfig file.

At this point I think my best bet is to focus on Typescript configuration, rather than dive further into alternative dependency managers like yarn. If you have ideas of how to get Typescript configured to respect a package's tsconfig settings then please leave a comment.

23