Create an EventCatalog Instance in a pnpm monorepo

Create an EventCatalog Instance in a pnpm monorepo

This article has been written with my friend Alessandro Magionami

Intro

Creating an instance of EventCatalog is an easy action:

npx @eventcatalog/create-eventcatalog@latest [name]

Unfortunately, instantiating it in a pnpm workspace (monorepo) is a pain in the ass.

This article describes this challenge and the solutions we applied.

  • If you want more context about the topic, start from the context

  • If you already know the context, jump to the challenge

  • If you already know the issue, jump to the solution

The context

EventCatalog is a fantastic tool essential to have at your disposal if your project is based on an Event-Driven architecture. Historically, the biggest challenge after implementing such an architectural model is undoubtedly creating excellent and adequate documentation to describe and present an event-driven system with domain separations, services, and responsibilities.

That's where EventCatalog comes in; it uses a descriptive markdown-based model to generate documentation in an EventCatalog instance!

Such a system follows a modular organization by adopting code and project organization practices like using a monorepo.

💡
A monorepo is a single repository containing multiple distinct projects with well-defined relationships. https://monorepo.tools/

Another important consideration in developing a solution is that not only the code but everything that supports it and falls within the development cycle should be as close as possible to the source code, the source of truth for the solution. This is especially true for documentation and even for an EventCatalog.

The challenge

While instantiating an EventCatalog using yarn and npm is straightforward, unfortunately, the same isn't true when using pnpm. Let's see why:

  • pnpm installs packages using a unique storage mechanism called "content-addressable storage," which stores each package version only once on the disk.

  • pnpm uses hard links or symbolic links to reference packages in the global store

pnpm does the magic of resolving packages, but unfortunately this doesn't work with some packages and tools requiring by design a different resolution and usage rules for packages. Thus, even if it is possible to create an EventCatalog project within a pnpm monorepo, unfortunately, it is not possible to build and run it from the monorepo since the build nextjs app references completely wrong paths to resolve packages.

💡
The explanation is a bit longer than this. If you’re interested in a deeper description of the issue and the why let us know and we’d consider enriching this content

The compromise

Pnpm can be heavily configured in what behavior it should have for a monorepo in this case, this is through the .npmrc file.

One of the configuration options permitting to have a working EventCatalog with a pnpm monorepo is by using the node-linker configuration:

node-liker=hoisted
💡
You can find repro at https://github.com/hoghweed/repro-pnpm-peer-deps-wrong-path with the solution mentioned, a description of the issue and drawbacks

In a few words:

  • go to your .npmrc file (usually at the root of your monorepo)

  • insert the line node-liker=hoisted

  • reinitialize the monorepo package installation

  • create an EventCatalog app within the monorepo using the same command as above in the Intro

Now you should be able to run and build an EventCatalog.

Even if this solves the issue, it introduces another issue by completely disabling the pnpm behavior with package installation producing a flat node_modules folder, no symlinks, no all the consequent benefits of using pnpm package management. ****

And that’s not the behavior we’d like to have.

The solution

There’s a better way to solve this, this permits us to save pnpm behavior and benefits while also having EventCatalog within the monorepo.

Let’s look at that in detail, basically, we’ll have the static, markdown-driven content inside the monorepo while the app and the required behaviors run inside a docker container.

💡
You can find a working demo solution at https://github.com/alemagio/test-event-catalog-docker

As you can see in the repo:

  1. The EventCatalog app has it’s own Dockerfile describing the requirements and steps to build an run the EventCatalog instance

  2. there’s a docker-compose file that

    1. uses the app Dockerfile to set the app for development

    2. mounts the static content volumes to compose a container to build the app

The repo is not using pnpm as expected since the behavior to test within that is the containerization of EventCatalog, and this is regardless the package manager to use

Conclusion

EventCatalog is a fantastic tool, pnpm even more, for several reasons, and it is a great thing to have both of them in use without compromises. By compromises, we mean giving up features, splitting repos, and reducing the DX. The suggested solution is an excellent way to solve the issue, permitting us to focus on the essential things, such as writing the content for good documentation, not how to build the application to serve it.

Now share your experience, solution or findings about that, we’d love to hear from you in the comments.

Call to action

If you want to know more about EventCatalog and pnpm we strongly suggest to:

Also if you want to know more about EDA, take a look at EDA Visuals. It is a fantastic content to help you through EDA and how to approach it.