This post was originally published on monades.roperzh.com
I felt compelled to write this because I've read many experienced programmers complain about the quality/quantity of npm packages in ways that are not helpful. Instead of providing a solution to the problem, this discourages new library authors to get started and this is unfair for the whole community: Imagine how many good packages we are losing! Imagine how many potential OSS collaborators we lost because they are worried about screwing up!
If you want to write your first JavaScript library, please don't be afraid, in this post I will try to walk you through the process.
Philosophy
Before starting, I'd like to make clear that the main rule governing this guide is simplicity.
Writing and publishing a node package should be a painless process, but It's possible to go overboard with all the tools available to enhance your workflow. While these tools are extremely helpful, they slow you down at the beginning.
The premise is to start small, and add tools as you need them.
Getting started
You'll need to have node.js, an updated version of npm
and Git. At the time of this writing I'm using:
- node.js v8.2.1
- npm v5.3.0
Code organization
All the code is contained in a single folder:
+-- mylib
| +-- index.js
| +-- test.js
| +-- // other files
- The
index.js
file is the entry point of your application, this is what the consumers of your library get when theyrequire()
/import
it. - The
test.js
file contains your tests. - There are other files lying around, all related to the configuration and documentation of your project.
note: As your project grows in complexity you may want to organize the code a bit differently. In that case, the convention is to create a folder called src
or lib
to contain your multiple source files, and a folder named test
for your tests.
For now, go ahead and create a folder to contain your project along with the index.js
and test.js
files.
Creating a package
Every project has a package.json
file, which contains metadata related to the project that is used by npm in order to identify the project as well as handle the project's dependencies; npm comes with a handy command (npm init
) to help you generate your package.json
in an interactive way.
When running the command, you'll be prompted to fill a couple of values that describe the project. Besides the basic stuff (package name, author, etc), there are two things to look at:
- Try to be thoughtful about the versioning of the package, when possible always try to follow semantic versioning.
- The license under which you're making your package available. Jeff Atwood has a good post on the subject. The MIT license is a good option.
For now, leave the test command
and git repository
entries empty, you are going to fill them later. This is what initializing a project with npm init
looks like:
§ npm init
This utility walks you through creating a package.json [...]
package name: (mylib)
version: (1.0.0) 0.1.0
description: This is a short description of my library!
entry point: (index.js)
test command:
git repository:
keywords: relevant, keywords, here
author: Roberto Dip
license: (ISC) MIT
If everything went right you should have a package.json
file at the root of the project.
Version control
If you are not sure what version control is or why you need it for your project, please read this tutorial.
Ignoring files
Version control is intended for files that people edit. Generated files should not be committed to version control. For example, do not commit binary files that result from compilation, such as .o files or .class files. Also do not commit .pdf files that are generated from a text formatting application; as a rule, you should only commit the source files from which the .pdf files are generated.
Michael Ernst, Version control concepts and best practices
You tell Git to ignore certain files in the project by creating a file called .gitignore
. This file contains series of patterns letting Git know which files or folders you don't want to track.
There are multiple templates out there if you're lazy to type, but for now, this is more than enough:
# Temporary files created by OSX
*.DS_Store
# Files related to development
node_modules
The first commit
Since you have done progress, it is a good idea to start tracking your changes. First, init your repository:
§ git init
Initialized empty Git repository in projects/mylib/.git/
Now add and commit your files:
§ git add .
§ git commit -m "Initial commit"
[master (root-commit) 88b12fb] Initial commit
2 files changed, 18 insertions(+)
create mode 100644 .gitignore
create mode 100644 package.json
Testing
To set up your test suite, you need:
- A library to perform assertions. At least for now, the built-in
assert
is more than enough. - A tool to run and report assertions. I like the simplicity of mocha
note: If in the future your tests grow in complexity, you can switch to any of the magnificent test libraries that JavaScript has.
Setting up mocha
The only thing you need to do is to install it via npm:
§ npm install --save-dev mocha
To make your life easier, you can run tell npm how to run your tests when you type the npm test
command by filling up the test script in your package.json
:
"scripts": {
"test": "mocha"
}
note: There is no black magic here, the scripts
object allows you to define arbitrary commands with npm run <command>
, since the test command is used so frequently, npm allows you to omit run
and call the test command directly.
Writing your first test
In your test.js
file:
// Require the assertion library
const assert = require('assert')
// Require you library
const mylib = require('.')
// Describe you library
describe('MyLib', function() {
describe('#hello()', function() {
it('should return a string representing a greeting', function() {
assert.equal(mylib.hello(), "Hello!")
})
})
})
And now, run the test with the command that you have previously defined:
§ npm test
If everything is right, the test fails (what a strange thing to say). This is because your library needs to export a hello()
method. Open index.js
and define it:
module.exports = {
hello() {
return 'Hello!'
}
}
And now the tests pass. The important thing to note here is the fact that you can easily require and invoke your library's methods, allowing you to test different outputs. It is always a good idea to cover as many edges as you can, this will make your code more solid in the long term, and will make you more confident when making future changes.
As you have done more progress, you should commit those changes:
§ git add .
§ git commit
tip: it's not always a good idea to git add .
and git commit
right next, I encourage you to check safer alternatives like adding git diff
and git add -p
to the mix.
README
In the README you let the world know what your project does, how to contribute, how to use it, and any additional information that you want your future contributors to know. A Beginner's Guide to Creating a README is a good source to learn how a good README looks like.
While you have the freedom to write it in any format, the standard format is markdown. If you're having a hard time with the syntax, here is a tutorial and here is a complete reference.
tip: dillinger.io is an online markdown editor that lets you preview what are you editing in real time.
note: some project files are named with UPPERCASE letters. This is an old convention that I've decided to stick with, the rationale is that makes the files easier to find for somebody new in the project.
Once you have a README.md file, don't forget to commit:
§ git add README.md
§ git commit -m "Add a README"
Publishing
The source
As soon as people start using your package they will find bugs, improvements, new features, etc. (that's the beauty of open source software). So, it's a good idea to make your code public to the world, allowing other people to contribute.
You can do this through Git, publishing your repository in a hosted git server like GitHub, GitLab or Bitbucket. It doesn't really matter where the project is hosted, you can always switch later on.
In order to publish the source you need to:
- Create an account in any of the services mentioned above.
- Create a repository.
- Grab the URL of your repository and push your changes.
§ git remote add origin [your-url-here]
§ git push origin master
And since you have your repository URL at hand, fill the git
entry in your package.json
:
{
"git": "[your-url-here]"
}
On npm
While publishing sounds scary, the process boils down to:
- Login (
npm login
) or register (npm adduser
) as npm user. - Run
npm publish
to publish your package. - Enjoy!
There are more detailed instructions at the npm docs.
Final Thoughts
The idea of this guide is to get you started developing your package. As for distribution is concerned, the process may vary a little based on which environments you want to support (node.js, the browser or both). By following this guide your package will be ready to run on node.js or the browser (depending on how you write your code). If you want to support both environments check out these resources, and if you still have questions feel free to reach me on Twitter or email.
Top comments (6)
Wonderful rundown! 👏👏👏👏👏
Thank you Ben! :)
Excellent! Thanks!
Thank you Erhan! :)
Really well done and written beautifully for beginners in NPM and Node.
Thanks for the kind words Brad :)