Profile ImageDaniel Bischoff
tagged in JavaScript • Mar 14, 20185 min read

Share code with yarn workspaces

The time will come when you want to share code between two or more projects. In this article I will show you how you can share your code with yarn workspaces.

You can find the code for this article under https://github.com/danielbischoff/yarn-workspaces-codesharing-example.

What are yarn workspaces?

Yarn workspaces enable you to have multiple npm projects that have a dependency on each other. It also detects common external dependencies and installs them only once. It does this by creating a node_modules folder at the root project and installing the dependency there. This is called hoisting. Yarn will also make sure that all projects share the same version of their external dependencies.

Before continuing, please make sure, that you have the latest yarn version installed.

Let's get started!

First let's make clear what we want to achieve. We want to create a very simple program that just multiplies two numbers. But we want the multiply function to reside in a shared project. Because I also want to show you how common dependencies are handled, we add lodash as a dependency to both projects (even if we don't use it in this example).

With yarn workspaces, we need a root folder with a special package.json file. Under the root folder we can put all of our dependent projects. I name our application's project folder app and the project with the shared code app-shared. So app has a dependency to app-shared.

So let's create the following folder structure:

code-sharing-example/
  app/
  app-shared/
  package.json

The folder named code-sharing-example is our workspace root. It contains all dependent projects and a package.json. In the next step, we need to add the following content to the package.json file.

/package.json

{
  "private": true,
  "workspaces": ["app", "app-shared"]
}

Here we need to set the property private to true, because the root project should never be published to the npm registry. The property workspaces lists all of our projects that reside under the workspace root.

The next step is to create a package.json file under every project.

app/package.json

{
  "name": "app",
  "version": "1.0.0",
  "main": "src/index.js",
  "dependencies": {
    "app-shared": "1.0.0",
    "lodash": "~4.17.5"
  }
}

app-shared/package.json

{
  "name": "app-shared",
  "version": "1.0.0",
  "main": "src/index.js",
  "dependencies": {
    "lodash": "~4.17.5"
  }
}

Build tools like webpack will put your compiled code under a special output folder (e.g. dist/). Make sure to set the value of main to this path. E.g main: "dist/index.js".

The magic part here is the dependency to app-shared in the app's package.json. It's also very important that you set the property main in the package.json of your shared project. Otherwise it tells you that it can't find your project. I also added the lodash lib as a dependency to each project.

So the last and most important thing that is missing, is the code itself. I will put the code under a src/ folder in each project and name the source files index.js.

app/src/index.js

const shared = require('app-shared');

console.log(shared.multiply(2, 3));

app-shared/src/index.js

exports.multiply = function(factor1, factor2) {
  return factor1 * factor2;
}

As you can see, the app's code requires the library app-shared and uses the exported function multiply. After these steps, the final structure should now look like the following.

code-sharing-example/
  app/
    src/
      index.js
    package.json
  app-shared/
    src/
      index.js
    package.json
  package.json

The final step is to let yarn install all your dependencies. So execute the following command in the root folder.

yarn install

After yarn is done, we now have a node_modules folder under root.

project structure after install

So yarn puts our project folders as sym-links (thanks vs-code for the sym-link icons) and also all dependencies that are used by both projects under node_modules.

To check that everything has worked, we now execute our app's index.js with node.

node ./app # prints 6

How to automatically detect all projects

Do you remember this line in the root's package.json file?

/package.json

{
  "workspaces": ["app", "app-shared"]
}

One downside with this solution is that we have to write every project to this array and after we have changed a project's name, we have to remember to update its name here.

But luckily yarn workspaces allows us to define our projects with glob patterns. So all we have to do is put the projects under a dedicated folder (often called packages), and update the value of the property workspaces.

After putting the projects under a folder named packages, the project structure now looks like this.

code-sharing-example/
  packages/
    app/
      src/
        index.js
      package.json
    app-shared/
      src/
        index.js
      package.json
  package.json

Now we only have to update the property workspaces in the root's package.json file

/package.json

{
  "private": true,
  "workspaces": ["packages/*"]
}

As you can see here, we replaced the project names with the name of the folder where we moved our projects to. The wildcard tells yarn to look under the folder packages for our projects.


I hope I could show you, how you can easily share your code with yarn workspaces. Thank you for reading my article!

Further Reading

Liked the article? Share it!

Tweet