What A Yarn Workspace Is, And The Problem It Solves
Published: 2020-10-27yarn workspaceswhat is a yarn workspaceyarn workspaces tutorialyarn workspaces example
What Is A Yarn Workspace?
Before I start to use a new technology, I first try to make sure that I really understand what it is.
This means getting the definition of what it is to be as crystal clear as possible for me, in all areas that compose the technology.
This is what we will first do with Yarn Workspaces before we dive into the way we can use them for our projects.
We can briefly state that a Yarn Workspace is a method of combining multiple project NPM dependencies into a single workspace, so that all projects share the same dependencies. This is commonly referred to as a ‘monorepo’.
To get an even better understanding of what a Yarn Workspace is, it's best to take a look at the broader picture of the problem it solves and why that problem exists in the first place.
The Multi-Megabyte Problem that a Yarn Workspace solves
While the emergence of open source packages within the NPM ecosystem has lead to tremendous benefits and time-saved on project code, the fact that so many node modules are now needed for even the simplest of projects has led to a lot of bloat in overall project size.
The average node js project, specifically the dependencies located within it, have a total estimated size of 76MB.
For a single, web based project for example, this is huge.
When working on more complex projects, with dependencies from a variety of frameworks, this size can swell even more. I’m sure we’re all familiar with the infamous Godzilla 500+ MB /node_modules folder.
Imagine now, with these large individual file sizes on each project, that we had a multi-project setup with each project that needed to have its own dependencies, such as what you might find in a standard MERN or MEVN stack. With a separate /client and /server folder structure, each with their own package.json and subsequent package dependencies.
Each of these projects would have to be loading in their own dependencies, and sometimes, as shown in the drawing above, having the same duplicate dependencies loaded in for each folder, causing massive unnecessary bloat. Not to mention the issues that would arise from dealing with out-of-date code and the potential conflicts in the overall codebase.
These issues are what are commonly referred to as ‘dependency hell’.
And it’s not a new issue. Infact, its been around for a long time.
Fortunately, there are now solutions to this problem. That solution as we have stated above is the monorepo.
One of the most prominent (within the NPM ecosystem) of which is the Yarn Workspace.
Whose benefits alongside the obvious bloat reduction mentioned above, include:
- Better code-quality and optimization due to packages being linked together. Leading to more up to date code in general.
- All your dependencies installed together at one time, leading to better ability for Yarn to optimize them.
- Yarn gets to make a single lock file rather than multiple, giving you fewer conflicts and making code review easier.
So now that we have a clearer overall picture of what a Yarn Workspace is in general. Let’s now take a look at what it actually looks like and how we can go about setting it up within a project.
How Do You Set Up A Yarn Workspace? And What Does It Looks Like?
Setting up a Yarn Workspace is as easy as running a few commands and making some edits to a few simple pages.
The general steps are:
1. Create your main project directory with a command like this:
$ mkdir my-monorepo-workspace
2. Navigate to the newly created project directory root and create your package.json.
$ cd my-monorepo-workspace
$ touch package.json
3. Replace the contents of your package.json with the following:
This makes the workspace project that we have created private, as we don’t want to upload it to NPM. It also creates the spaces where we will set our workspace project names and our scripts.
4. Create two project directories within your main directory root, like this:
$ mkdir project-1 project-2
Feel free to name these however you want.
5. Add your project names to the workspace package.json that lives within your root directory:
"workspaces": [“project-1”, “project-2”],
Once set up, these two of our projects will be able to share the same installed NPM packages.
The above steps have now given us our basic Workspace structure.
Now we can get started with fully activating our Workspace. Let’s add some real code to it before we do that, to demonstrate how it all works.
We’ll do this by creating a front end in project-1 and a backend in project-2.
6. For our front-end in project-1, we’ll use React, which we can install with the following command:
$ yarn create react-app project-1
7. For our backend in project-2, we’ll use an Express.js server package. Which we can install by first adding Express Generator to our global package.json like so:
$ yarn global add express-generator --prefix /usr/local
Note: Notice here that we use ‘yarn global add’ instead of the usual ‘yarn add’, now that we have multiple projects, we need to specify the scope of our installed packages for clarity.
8. Generate and install the Express package for our server in ‘project 2’ like this:
$ express --view=pug project-2
Now that we have set up our react app frontend and our express app backend we can now install all of our dependencies.
9. Install all of the dependencies like so:
$ yarn install
This command generates a yarn.lock file, which contains a note of all of your dependencies. This is generated automatically and should not be deleted.
Our packages our now installed and should be available to both of our projects within the workspace.
As a final step, let us now set up some scripts that can run our projects for us concurrently, which is wise to do within a shared workspace, as the core concept is about bringing these two together.
10. We can set up the two projects to run concurrently by first setting the command within our root package.json like this:
$ yarn add -W concurrently
This adds the ‘concurrently’ start script that you’ll see below that runs the two project start scripts concurrently.
To tell our package.json how we want those scripts to run, add the following:
"workspaces": [“project-1”, “project-2”],
"project-1": "yarn workspace project-1 start",
"project-2": "yarn workspace project-2 start",
"start": "concurrently --kill-others-on-fail \"yarn project-2\" \"yarn project-1\"
The actual scripts that are necessary to run the projects are within the installations within the project directories.
Last but not least, change the port name within our project-2 express app directory to port 4000, just to ensure that we don’t get conflicts by running the same port 3000 when we run our two app projects.
11. We can do that like this, within our server/bin/www on line 15:
var port = normalizePort(process.env.PORT || '4000');
Now to run our project, all we need to do is go to our root directory and run:
$ yarn start
That’s it, we’re done.
This has fully set up our Yarn Workspace, and has it running!
If you’d like to read some more on the topic of Yarn Workspaces, as well as monorepo's in general. Here are some good resources:
Creating Yarn Workspaces with GatsbyJS - https://www.gatsbyjs.com/blog/2019-05-22-setting-up-yarn-workspaces-for-theme-development/
Yarn Workspaces: Organize Your Project’s Codebase Like A Pro - https://www.smashingmagazine.com/2019/07/yarn-workspaces-organize-project-codebase-pro/
What Is a Monorepo? - https://www.perforce.com/blog/vcs/what-monorepo
This is a post on StackOverflow that will help in modifying a Yarn workspace that has already been setup when that is necessary for you to do.
Check out the easiest way to plan your website or mobile app. Try PlanFlow for free.