How to publish a npm package in four steps
You’re a junior developer that recently landed on the JavaScript ecosystem. There’s so much going on that you have no idea where to start. Maybe try React? That library is cool, I should try it. Why isn’t this working?
One thing that I found is that being part of the ecosystem is the quickest way to understand it. That’s why in this article you’ll learn how to publish a npm package and get it working in your projects as fast as possible.
We’ll be using babel and webpack 4 to ship compact and idiomatic JavaScript code.
You can clone the repo that contains all the code from this article and follow along, or start from scratch.
git clone git@github.com:vmarchesin/how-to-publish-a-npm-package.git
The code is split into four branches, and I’ll explain where we are at each point. If you get lost, just jump into the next branch and you’ll catch up. The master branch has the finished package ready to be shipped.
Step One
First, we need to install our dependencies. We’ll be using babel and webpack, which I recommend for every project. You’ll see that our library is so simple that this wouldn’t be necessary, but we’re doing it for learning purposes.
It’s good to setup a Github repository for your npm package beforehand, if you’re not using my sample. You can find out how to create one here.
Run npm init
inside your git directory and follow the prompts. If you don’t know what to put in a field, just leave it blank.
Install all of the dependencies by running:
npm i -D @babel/core babel-loader webpack webpack-cli
npm i
is a shorthand for npm install
and -D
is a shorthand for --save-dev
which means you’ll be saving these as Dev Dependencies (they won’t be shipped with your code).
Also let’s create a .gitignore
file so you don’t accidentally commit the node_modules
folder. Just add node_modules
inside the .gitignore
file and you’re good to go.
A good practice is to add a README.md
file so people know what your library is about. Create one.
If you want to jump to this point, just checkout the step/one
branch. If you do this instead of installing the packages yourself don’t forget to run npm i
to install everything.
Step Two
Now it’s time to write our library. Let’s implement a random number generator. Let’s call it choice
in honor of Python, even though it has nothing to do with the actual Python method.
Our file structure should look like this:
|-src/
| | bool.js
| | float.js
| | index.js
| | integer.js
| .gitignore
| LICENSE
| README.md
| package-lock.json
| package.json
If you don’t have the LICENSE
file, don’t worry. You can copy mine and just change the copyright to your name. The MIT license is a very permissive license, and enables people to freely copy and/or modify your code as long as they credit the original source. You can use any license you desire.
The code for each file inside the src/
should look like this.
We export the choice
method, that expects a max
, min
and options
arguments. If we pass { float: true }
as the options object we get a random float, if we pass { bool: true }
we get a boolean, and if we don’t pass anything we get an integer.
We’re able to use the import
and export
syntax because we’re using babel. We haven’t configured it yet, but we will on the next step.
If you want to jump to this point, just checkout the step/two
branch.
Step Three
Now it’s time to create our bundle. At this point you could just ship the src
folder and it would work, most of the time (ours wouldn’t because we’re using import
and export
, but you could just change to require
and module.exports
to make it work). We can do better.
Webpack is a module bundler, meaning it does a better job than you in shipping code efficiently. It’ll minify and, alongisde babel-loader, transpile your code to be exported as a CommonJS
module. CommonJS defines a module format and makes it readable by most JavaScript environments.
We’ll put our webpack config in a file called webpack.config.js
.
We just defined our webpack configuration. mode: 'production'
enables various performance improvements in our final bundle. entry
defines the main file in our module, which is the default export. output
defines where our module will be exported, in this case it will be the file dist/index.js
. The rules
section inside module
tells webpack to use babel-loader on all .js
files, and the resolve
section is there so we don’t need to add the file extension on our import
statements.
Now that we configured webpack we need to tell our package.json
how to build our module. Make sure you have this inside your package.json
:
...
"main": "dist/index.js",
"scripts": {
"build": "webpack --mode production"
},
...
Our main
file is the one that will be called when we declare our module as a dependency. As you can see it’s the file generated by webpack. Also define the build script.
Now just run:
npm run build
You’ll see the dist
folder created. You don’t want to publish this folder to your Github repo, so add a new line inside your .gitignore
telling you don’t want dist
to be staged.
If you want to jump to this point, just checkout the step/three
branch.
Step Four
We’re almost ready to publish our package! Now, before we publish we need to make sure it’s working. We can use npm link
to test it. npm link
Creates a virtual link to a module, simulating a npm install
.
Follow these steps:
- Inside your module directory run
npm link
to create a virtual link to this module. - Find yourself a project you’re working on, and run
npm link <your_module>
inside its folder. Take a note here, your module name isn’t the directory name your module is in. It’s the name declared inside yourpackage.json
file. - Import/Require your module inside your project and test it. It’ll be treated as if it was installed as a dependency.
If something isn’t right all you need to do is update your module and run npm run build
again. It’ll automatically update your virtual link and reflect the changes in your project so you can test it.
By the time you are done just run npm unlink
inside the module directory and npm unlink <your_module>
inside your project directory.
If everything is working, it’s time to publish. The short version is:
- Create a
.npmignore
file - Create an account on npmjs.com (if you dont’t have one)
- Run
npm login
- Run
npm publish
inside your module directory
Let’s break it down.
Create a .npmignore
file in your root folder. It acts the same way as .gitignore
does, but tells npm what you want to discard from the final module. Put src
and webpack.config.js
inside .npmignore
, as we don’t want our source code and the webpack config to be bundled with our module.
Create an account on npmjs.com if you don’t have one already. You’ll need it to publish your module under your account. After the account is ready, run npm login
in your machine and fill in the credentials.
Now, inside your module directory run npm publish
. It will retrieve the version
defined inside your package.json
and publish it to npm using the same version. You can’t publish again using the same version, or a previous one. You can read more about versioning here.
Don’t forget to build before publishing. If you don’t you will end up publishing an empty module.
Article update: You can avoid this problem by adding a prepublish
script to your package.json
. This will ensure that the build will always run before you publish your package in case you forget to manually build it. Just add the script to your package.json
.
...
"scripts": {
...
"prepublish": "npm run build"
},
...
One more thing: if you try to publish your package using the same name as the one from this article, how-to-publish-a-npm-package
, it won’t work. Make sure the name of the package inside your package.json
is different.
If you want to jump to this point, just checkout the step/four
branch.
You’re done!
Now you can install your module inside any project! Find one and try it out:
npm i -S <your_package_name>
You can try this package too:
npm i -S how-to-publish-a-npm-package
You can check the package at npmjs.com as well:
Now go out there and publish. The open source community awaits you.
You can find me on my website. Thanks for reading this article.