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: myApp
is 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?
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.
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.
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.
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 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.
Top comments (6)
Thanks man, your post saving my day
Thanks a lot!
Thanks dude, I wish I had seen this post earlier. It would have saved a lot of mine and my teams' time.
Saved my day!
What about HMR in the module? Do I need to run build on every change in my module?
Yes, because this way you are linking to the already build version