Unsolving the mysteries of yarn/npm link for libraries development

Mariano Cocirio
5 min readJun 12, 2019

Introduction

Imagine you are developing a web app, that web app belongs to a family of web apps who shares the same style in their visual components, which means that you are probably going to build a UI library to centralize all your components. That will give you the possibility of changing some behaviour, even look and feel of specific components across all your applications by just modifying that library.

Now we have an issue: How do we test our library integration with the rest of the ecosystem locally without releasing a version every time we modify something? That’s a common bad practice that you’ll see at some companies, just releasing beta/minor versions to test stuff as they don’t have a local way to test the integration of the library with their apps.

Testing the individual components from your library can easily be done by using for example Storybook, but the integration with the rest of your applications is the tricky part, here is where you should use yarn link , the idea behind this is pretty simple: It just creates a symlink to whatever you point to.

Time to add some real work

Let assume we have the app myApp who uses myLibrary-UI , being myLibrary-UI the UI library that provides all the base component to myApp . You are gonna have something like this in your package.json :

Right now when we run yarn we can say that it generates the following structure: myAppis going to contain our library in its package, but if we want to use the local version instead of the published version, how do we override the version it uses?

Our app containing our library

It’s pretty simple, you should just build your library locally, then you run yarn link in the directory you build it, by doing it you’ll register your package locally. After this, you should just go to the root directory of your application and run yarn link "@yourCompany/myLibrary-ui" , this will create a symlink to your local copy that will be resolved before the copy installed by yarn.

WARNING: if you run yarn again, this link might disappear, you’ll need to run the last command again.

Our app linked to our local version of the library

By now we already have our app running using our local version of the library, this way we can easily test the integration of the new version with our app, and we can also use it to prepare our app to adopt any breaking changes from our library in case we need a simultaneous release. This might seems to be pretty straight forward but now is when the real issues begin.

Multiple definitions

I’ll assume we are using React in our library, but we are also using React in our application, this should be easily solved by our package manager while installing them in a regular way.

React is just installed at the top level, then used by children

But as we are linking it locally we have the problem of multiple React definitions in our project, this gonna generate multiple errors that are not that easy to debug and really not very descriptives, like for example:

Unhandled Rejection (Invariant Violation): Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.`

React is defined two times causing errors

The easy way to fix it is by using the link command, we just go to our library and we create a link from there the React definition in our application, something like this: npm link "../myApp/node_modules/React” . This will create a symlink in our library to the React definition in our app. The result is our project will only use the React definition in myApp but it will run our local version of myLibrary-UI .

Now we are using just the main definition

Now you are able to develop your library and test its integration with your apps locally just by using link commands. There are other ways to avoid multiple definitions, for example, let’s say we are using styled-components in both packages, but our app is also using NextJS, we can solve this issue by adding the resolver for this specific package in Webpack configuration:

Conclusion

Sometimes it’s really important to test your library locally so you can test its integration with other apps that use it. That’s really tricky sometimes but it helps you a lot to develop a better library.

By using link command you can easily achieve a configuration that allows you to test your libraries in a local environment, saving you from making for example test releases to check the integration.

Hope you like this article and most important I wish you find it helpful, I’ve been fighting with issues to test integrations between multiple packages a couple of times, some of this came out after several fails by myself.

--

--