Monades

Bootstrapping a JavaScript Library

July 27th, 2017

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:

Code organization

All the code is contained in a single folder:

+-- mylib
|   +-- index.js
|   +-- test.js
|   +-- // other files

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:

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:

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:

  1. Create an account in any of the services mentioned above.
  2. Create a repository.
  3. 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:

  1. Login (npm login) or register (npm adduser) as npm user.
  2. Run npm publish to publish your package.
  3. 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.

by Roberto Dip

Web Developer passionate about OSS