Hello guys, and happy new year! I hope you are doing well.
So, being my first time publishing a library (in a correct way.. 😅) I searched for a good way to do it on the web essay, but the problem I encountered is that there are a LOT of different ways to do it, some people use webpack, some others use rollup, some actually does not use nothing.. and others again use Bit, everyone telling that theirs is the "definitive way to do it", and for me (and probably for most of us), it was a bit confusing to find a sort of 'standardized' way to do it.
The topics that will be covered in this article are:
There will be also an article about how to manage the versioning of your library. I will attach it to this article, when it will be ready.
The first thing that you need to understand before publishing a library, is actually how it's read by the project that uses it. It is a very simple, but important concept that you must know. So let's start with an example. Let's pretend that we have a project called "my-project" that uses the library "react-plock" we just published 🙋. In order to use it, we need to import it in our project.
The question is: how the fu*k is the library "react-plock" read by the project "my-project"?
Let's try to answer this question looking it from another perspective. Imagine you have in your amazing "my-project" a custom component made by you called
Banana, and you wanna use it in the App component. How can you accomplish this?
Notice that the only thing that's changed from the previous example is the path to the component source code, that in this case, is a relative path, not a library name.
In turn, the
Banana could be structured like this:
So, the App component imports the
Banana component, by reading an exported function called
Banana from the
Note: There is also the default export available as option, but i personally prefer the named export when i work with modules.
Well, but, how about the
By now you should have understood that in order to import a module, you need to specify two fundamental things. The first one is the path to the module, and the second one is the name of the module.
To import an external library, our beloved
package.json will come to our aid. It's a file that contains all the information about a library, and every library has its own
If you have a look at the (
package.json)[https://github.com/itsrennyman/react-plock/blob/main/package.json#L6] file of the
react-plock library, you'll see some intersting information that i will highlight for you:
Did you notice the
main property? It's the path to the library source code. This is the file that will be imported when the library will be used!
Sooo, returning to our question, how the library "react-plock" is read by the project "my-project"? I attach again the initial example to avoid you scrolling again to the top of the page:
Guessed? Well, once the App.js file is included, and it evaluates the Plock import, node will look for the
package.json file of the
react-plock library (included in the node_modules folder of your project during the installation), once it finds it, it will read the
main property and will import the library source code!
mainproperty can be any file generated in your library, but the most common way to do it is to use the
We will create an amazing library called
gimme-a-pokemon, and we will publish it on npm. The package will provide a function that will return a random pokemon name from an array (The package of the year 🌻).
Let's start by creating the index.js file of the library. This will be our
main file in the
package.json, and it will contain the function that will return the pokemon name. We will use the commonjs syntax to export the function in order to be compatible with older versions of node and not use any transpiler in the process. In a second step we will add the transpiled version of the library to the
The code is pretty simple, call the
gimmeAPokemon function and return a random pokemon name.
We will skip testing the library for now, due to the fact that it's very simple.
Now it's time to create the
package.json file. This file will contain all the information about the library, and it will be used by npm to publish it. You can run the following command to create the
npm init command will create a
package.json file in the current directory, and it will ask you some questions about the library.
After the command is executed, you will have a
package.json file in your current directory, here's a quick description of some of the properties in the file:
| Property | Value |
| ------------- | ------------------------------------------------------------------ |
name | The name of the library |
description | A short description of the library |
version | The current version of the library |
private | If the library is private, it will not be available for the public |
main | The path to the library's main file |
files | The files that will be published on the registry |
author | The author of the library |
license | The license of the library |
Note: There are some keys like
fileswhich are not present by default. Also, there are other keys that you can use, but there are out of the scope of this article.
This is the
gimme-a-pkmn real library example, i omitted for this example the useless keys like
keywords, etc.. you can look at the entire file here
Once you have configured the file, all we need to do is to login in your npm account, and publish the library.
And that's it! The library is published on npm with the version
0.0.1 and you will be able to install it in your project using
npm install gimme-a-pkmn.
Yeah our library works great, but we can't use the ES6 features in our code. Or better, we could, but not every environment supports ES6, so we could have a problem. Let's see how to solve this problem using a transpiler.
Unpopular opinion: Transpilers are simple. They are just a tool to convert ES6+ features to ES5.
I told you this because if you look at almost every tutorial on the internet you will see tons of line of webpack, rollup configurations without any explanation of what they actually do. So it may scare you, but trust me it's not a big deal. I will explain you like i would explain a child.
The concept is simple, as i said just before, transpilers are just a tool to convert ES6+ features to ES5, so they takes an input file and output a transpiled file. This is currently all you need to know about transpilers. Simple right?
Look at this example, this is a modern arrow function:
If you try to run this code in an old browser, you will see that it will not work. In order to fix this, we need to use a transpiler. Let's see how the code becomes after the transpilation:
Did you see the difference? The transpiler will convert the arrow function to a regular function, and it will add the
function keyword and the
You can so some experiments with this configuration here.
Obviously there's a lot more to know about transpilers, but for now, let's focus on the basics.
Another scary name you should know is bundler. Bundlers are tools that take a bunch of files and compile them into a single file. Usually are useful because they have also a lot of plugins, so you can easily integrate a transpiler like babel we just saw, with a bundler. I personally find rollup the bundler which i'm most comfortable with. So we will use rollup with its babel plugin to compile our code, don't worry, it's not a big deal.
So, our goal now is: we want to use rollup to bundle our code, and we want to use babel to transpile our code. Let's see how to do it.
First, we need to install the rollup and babel plugin packages as dev dependencies.
Once the packages are installed, we need to create a
rollup.config.js file. This file will contain all the configuration for your bundling process.
Please take some time to read again the code, it's pretty simple, but it's important to know how it works. Remember, also in bundling there is an input, and there is an output. And the process between is called bundling.
Ok now we need to add a command to run the bundler. Again we will use the package.json file, we can insert a new script called "build":
And the last thing we need to do is to change the
main property of the package.json to another destination, otherwhise our
index.js file will be overwritten. Also the
files property will be updated as well because we need to publish the dist directory.
Now we are ready to run the bundler. Go ahead and run the command
npm run build. You should see the bundled file in the just created
dist folder. Check the differences between the two files! 🥸
Now your code can be used in any modern browser, and it will work just fine. You can also rewrite it using modern ES6 features:
By running the command
npm run build again, you should see the bundled file with the new code, fully compatible with modern and old browsers.
You can also publish your new code to npm, just run the command
npm publish. But remember to bump the version number in the package.json file, otherwise the new version won't be published.
Soon i will publish also a detailed guide on how to manage the version of your libraries, totally automated, using Github actions. So stay tuned!
If you have any questions, feel free to contact me on Twitter.