Building a Swiss Army Knife: How to Reuse Code with Monorepo Packages
Building a Swiss Army Knife: How to Reuse Code with Packages
We explore two solutions: multiple repositories and a single repository (monorepo). We opt for the second option and present some tools, like Turborepo and Changeset, to help manage a monorepo efficiently. Then, we build an architecture with multiple applications and packages. This architecture is ideal for companies with multiple applications and shared components, which seek a scalable approach to software development.
It is very common for companies to have more than one application, for example:
1 - Application for the client (CLIENT).
2 - Application for system administration (ADMIN).
3 - Several other applications.
With these applications, there will certainly be overlapping code. For example: basic components that can be shared using the famous Design System.
This Design System can be an internal company package, or even public. In addition, these applications can consume similar APIs and we can have an SDK that implements the calls to facilitate their use.
With the scenarios in mind, how can we organize and build our Swiss Army knife?
- One solution would be to have multiple repositories for each application and package; and upload the packages to NPM Packages or GitHub Packages.
- This solution can be good when the company has several teams and wants to segregate access to the codes, but it can be very laborious for small teams, when the architecture is not yet very mature, since local development requires the use of symbolic links (yarn link or npm link) to reference the packages and do local development.
- Another solution is to have a monorepo (single repository) with the applications and packages that can be published on NPM Packages or GitHub Packages (can also be used locally as they are in the same repository).
- This solution is great for small teams starting their design system and api architecture, aiming for decoupled code and future sharing of public packages.
In this article we will use the second option, but first let's define some concepts and tools:
- A Monorepo (Monolithic Repository) is a source code management model where all an organization's code is stored in a single repository, rather than being split into several smaller repositories for each project. The goal is to simplify code management and enable easier and more efficient collaboration between teams.
- The Changeset library is an extension of the monorepo ecosystem, designed to simplify the way code changes are tracked and managed in a monolithic repository. With Changeset, developers can group changes into sets (called "changesets") and assign those sets to specific packages in a monorepo.
Let's get to work! We will build the following architecture:
- App Client: Vite application for the client;
- App Admin: Vite application for admin;
- Package Core Api SDK: SDK package for using APIs;
- Package ESLint Config: Package to share ESLint settings;
- Package TS Config: Package to share Typescript settings;
- Package Design System: Package to share UI components.
Step by step:
- Fork or copy the base repository.
Your repo can be public or private. It depends on how you want your project. Remember that certain features on the free account are only available for public repositories like Github Pages. Learn more.
- Create a personal access token.
You will need this personal access token to create your packages. So create this key with the following accesses (learn more).
- Add the created key as a secret in the repository.
Save the created key as a secret in the repository to be consumed by the actions in the package deploy flow. Suggested name: GH_REGISTRY_PACKAGES. This name will be used in the deploy workflow. Learn more.
- Add permissions in your repository for the workflow.
Your package deploy workflow will need to read and write to the repository in addition to creating pull requests to approve new versions. Learn more.
- Add permissions in your repository for GitHub Pages.
As we need to build our assets before deploying, we will use Github Actions. For this it is necessary to give the workflow permission to upload the assets to GitHub Pages. Learn more.
- Clone your repository to your machine.
Run the following command (learn more):
git clone email@example.com:kibolho/monorepo-scaffold.git
- Increment the version of your package.
Run the following command
Now just commit and the workflows will be triggered.
Approve the pull request created by Changeset.
Package created and ready to use.
Now we have the package created and it can be downloaded using the GitHub registry.
- Using the package.
The default registry is NPM, so to download the package from GitHub you need to point to the GitHub registry.
And if you want to use the packages privately: Create or edit the ~/.npmrc file and replace PERSONAL-ACCESS-TOKEN with your token created in step 2. The ~/.npmrc file is responsible for NPM's global settings.
As you could see, the focus was more on architecture, I didn't go too deep into the code because there are many technologies involved, maybe in future articles I'll go deeper! Some observations:
- The Client application in the code was left with just the Vite Hello World, since the concept was shown in the Admin application;
- I created a workflow that deploys the Client and Admin application to different S3 buckets since GitHub pages does not support multiple applications per repository, let's follow this feature suggestion here.
As the repository is public feel free to propose improvements 😀 like:
- Deploy on Vercel;
- Evolve the design-system and api-core-sdk packages with public APIs;
- Create a real application on top of the architecture.
Final Admin Application - https://kibolho.github.io/monorepo-scaffold/
Until next time!