Skip to content

Setup as monorepo

Piyal Basu edited this page Jul 31, 2020 · 3 revisions

Why combine all Lyra affiliated packages

At the beginning of the project, it seemed we would just need an extension and some docs. I conceived this repo to just be the code for the extension with another repo holding the docs content and build tools to launch a docs website.

As we progressed we realized we wanted to have an npm package to serve as a wrapper around the messaging system to make it easier for clients to integrate in a standard way. Further complicating matters, was that this package would need to share some helper functions/constants/types with the extension code.

In addition, docs would need to pull in the client facing API wrapper. All of these things being interdependent meant having them in one place would prevent us from having to constantly be publishing and updating different repos.

Why use a monorepo

The most obvious benefit of this is keeping all Lyra code under one roof. Making a change to any one of these subrepos would likely trigger a change somewhere else. (For ex: making a change to the extension background would necessitate a change to lyra-api, and likely the docs as well).

Really, putting everything in one repo could have been done with relative paths, but it would have become a bit of a mess. I used Yarn workspaces to split each project (the extension, docs, client facing API, and shared methods) into its own repo with its own configuration, dependencies, package.json, etc. Yarn workspaces dedupes duplicate dependencies by module hoisting, making the installation process much easier and faster. It also symlinks all subrepos, meaning you can import any subrepo like a normal npm dependency. All of this comes "free" with Yarn without having to install/setup/learn a framework like Lerna for a pretty simple task.

Monorepo in action

All the of the existing extension code was moved to a folder called extension. Separate folders were created for the client facing API (tentatively called lyra-api) and for the core shared functions (called @lyra). Docs will be its own folder in this repo, as well, with a deploy strategy defined in that workspace. The root folder contains the base tsconfig and eslint config. If a subrepo needs to make a change to any of these settings, they will extend the applicable configs in its own folder.

Issues

The only complication is that we need to publish only one of these subrepos to npm (the client facing API). This is an issue because this project had @lyra as a dependency. This works fine locally because when you build this code inside the monorepo, it can find the local repo @lyra by symlink and compile this code. However, if you were to package a tarball of this module (using yarn pack) and try to install it in a different project, it would look to the npm registry for the a dependency called @lyra, which does not exist to the public.

This is sort of an edge case with yarn workspaces, though not one that seems to be getting much attention.

To combat this, in the client facing module, we are importing @lyra using a relative path rather than using a symlinked dependency. This tells yarn pack to include the @lyra folders in the tarball, making all the needed dependencies available to the end user. This is not ideal, but a usable workaround until we find a better solution for this.

Ultimately, this issue not withstanding, yarn workspaces provides enough convenience in dep deduping and symlinking that it is still worth using.

Clone this wiki locally