Publishing an NPM Module Part 4

These are my notes based on the phenomenal tutorial by Kent C. Dodds hosted by egghead.io both of which are my go to sources when I want to learn something new. I highly suggest you sign up for the pro subscription.

Part 1 | Part 2 | Part 3 | >Part 4 | Part 5 | Part 6 | Part 7

Part 4: Automating Releases

As developers we should be looking to automate as much as we can. Setting SemVer values is certainly one we should do. One reason is to reduce how much we have to remember for regular tasks, another is removing emotion from versioning. Check out this video for some other nifty reasons. It is pretty straightforward to set up.

First let’s install it globally.

$ npm install -g semantic-release-cli

Now that it is installed we can run through a nice little wizard to configure it. Making sure you are in your module folder type:

$ semantic-release-cli setup

There are several prompts:

  • Whether your GitHub repository is public or private
  • Which NPM registry you want to use (Default: https://registry.npmjs.org/)
  • Your NPM username (unless passwords were previously saved to keychain)
  • Your NPM email
  • Your NPM password
  • Your GitHub username
  • Your GitHub password (unless passwords were previously saved to keychain)
  • Which continuous integration system you want to use. (Options: Travis CI / Pro / Enterprise, or Other)
  • Whether you want to test a single node.js version (e.g. – 0.12) or multiple node.js versions (e.g. – 0.10, 0.12, etc.)

Enter your information, most of them will default to the right one, just make sure for the CI question that Travis-CI is chosen and for the node version select single node.

Let’s see what happened! Looking at package.json we see a new script semantic-release.

"semantic-release": "semantic-release pre && npm publish && semantic-release post"

Also notice that the version section of package.json has vanished. Travis-CI will handle that now, however to suppress a warning message when we release the npm package let’s add it back in as:

"version": "0.0.0-semantically-released"

It also updates the url to https and adds semantic-release to the dev dependencies. Let’s configure travis.yml a little by adding our test script in the chain, between before: and after: add:

        Script:
        - npm run test

This will make sure that our tests are run when our CI attempts to publish them.

glyphicons-28-search To learn more head over to the modules readme here.

Being a good Commitizen

Let’s install commitizen to help us keep our commit messages consistent in order to help our versioning system to be even more emotionally agnostic.

In your terminal run:

$ npm i -D commitizen

Next we need to tell it which standard to follow for our messages. I go with a fairly standard one used by the AngularJS team called… conventional changelog!

glyphicons-28-search You can read more about it here.

To install it simply type:

$ npm i -D cz-conventional-changelog

glyphicons-499-sunglasses If you are pretty settled on these then you can install them with -g instead of -D. If you do that there is a bit more setup involved. Go here for more info.

This adds bin to node-modules for us to use in our npm scripts called git-cz. You could just run the following instead of git commit:

$ git cz

glyphicons-499-sunglassesYou can use all the git commit options with git cz, for example:
git cz -a.

However we are going to set up a script in our package.json to make things a little cleaner and a bit more obvious. Simply add a new script with the following:

"commit": "git-cz"

Then we need to tell it to use our cz-conventional-changelog, in the config section (create one if you don’t have one) add:

 "config": {
    "commitizen": {
        "path": "node_modules/cz-conventional-changelog"
    }
  },

Let’s stage these changes.

$ git status
$ git add -A
$ git status

Before we run our new nifty script head over to your repo on github and create an issue. For this let’s make it something like “standardize commit messages”. This is probably your first issue, however if it is not take note of the number and use that for the final prompt.

Now that everything is staged we can run (on the last prompt put closes #1):

$ npm run commit

Automatically Releasing with Travis-CI

$ git status
$ git push

Look at the repo and notice the closed issue. Go to travis-ci.org/the-name-of-your-repo notice the problem? It is stuck at the testing phase. This is because we have a -w on our test command so it will never close. To fix this we are going to add a script to our package.json:

glyphicons-424-git-create
“test:single”: “mocha src/index.test.js”

We also need to edit .travis.yml and change our npm run call:

glyphicons-424-git-create
- npm run test:single

Go back to travis-ci.org and cancel the build.

Let’s try that again in your console:

$ git status
$ git add .
$ npm run commit

Now watch travis-ci, note the version number change. Look at github release, look at npm see how the version change has propagated across the multiple distributions.  We are cooking with gas now!

Next… Automating Testing and Code Coverage!

Key:

glyphicons-55-clock  = Time Saving Idea

glyphicons-499-sunglasses = Pro Tip

glyphicons-31-pencil = Note

glyphicons-197-exclamation-sign = Alert

glyphicons-424-git-create = Code Update

glyphicons-28-search  = A Closer Look

Publishing an NPM Module Part 3

These are my notes based on the phenomenal tutorial by Kent C. Dodds hosted by egghead.io both of which are my go to sources when I want to learn something new. I highly suggest you sign up for the pro subscription.

Part 1 | Part 2 | >Part 3 | Part 4 | Part 5 | Part 6 | Part 7

Part 3: Setting up Unit Testing

There are tons of testing libraries out there. I am going to stick with the more common ones mocha and chai for now. In later parts I will introduce a few more. In order to use them we should install them!

Head to your trusty console:

$ npm i -D mocha chai

glyphicons-499-sunglasses  the above is the same as ‘npm install mocha chai –save-dev’ only faster!

Create index-test.js in the same directory.

$ touch src/index.test.js

Now looking at our index.js we see we have a few things to test. At least 4 since we do have 4 methods.

module.exports = {
    list: list,
    single: single,
    startsWithLetter: startsWithLetter,
    numberOfNames: numberOfNames
}

Let’s start building our index.test.js. We will first wrap our initial section in a describe block. This is just a container to describe what we should expect to see tested inside.

var expect = require('chai').expect;
var rng = require('./index');

describe('Our first tests', function () {
   
});

Our list method should return an array containing strings. So let’s test for that!

describe('tests should be running', function () {
    describe('list()', function () {
        it('Expect it to return an array of strings', function () {
            expect(rng.list()).to.satisfy(isArrayOfStrings);

            function isArrayOfStrings(array) {
                return array.every(function(item){
                    return typeof item === 'string';
                })
            }
        });
    });
});

glyphicons-28-search Let’s take a closer look at each part in the above test. We have another describe block, this time focused on the all method. This is a nice way of grouping our tests to keep them focused. The first argument in describe is a string denoting the topic, the second is a function that will contain our actual tests and also could be used to set up mock data if we needed it.

The it is similar to describe in that you first give it a string but this time it will be much more specific. This is what you are actually testing. In this example we want to make sure that the all function returns an array of strings. The second argument is again a function block where we will do the specific test.

One of the benefits of this style of testing is to create very readable tests. Even if you don’t know the nitty gritty you could read the test and it will explain itself. Using expect or should gives you a clear idea of what we are looking for. They are pretty similar, however there are some syntactical differences to be aware of. (read more)

These allow you to chain together natural language assertions. Expect takes the value you want to test and then you chain together what assertions you need to use in order to test. The language used to chain the expect and the test generally do not  provide testing functionality.

List of Chains:

    .to
    .be
    .been
    .is
    .that
    .which
    .and
    .has
    .have
    .with
    .at
    .of
    .same

These get chained together finally ending in an actual test assertion. For example in my test we see:

expect(rng.list()).to.satisfy(isArrayOfStrings);

This means that we expect that when we execute rng.list() that it will satisfy the given truth test. Here our truth test is another function that checks to see if every item in the array has a type of string.  This is very flexible and will help you easily generate tests. The full api can be read here. Here are some of the ones I use most:

.match(regexp)

  • @param { RegExp } RegularExpression
  • @param { String } message _optional_

Asserts that the target matches a regular expression.

expect('foobar').to.match(/^foo/);

.instanceof(constructor)

  • @param { Constructor } constructor
  • @param { String } message _optional_

Asserts that the target is an instance of constructor.

var Tea = function (name) { this.name = name; }
  , Chai = new Tea('chai');

expect(Chai).to.be.an.instanceof(Tea);
expect([ 1, 2, 3 ]).to.be.instanceof(Array);

.equal(value)

  • @param { Mixed } value
  • @param { String } message _optional_

Asserts that the target is strictly equal (===) to value. Alternately, if the deep flag is set, asserts that the target is deeply equal to value.

expect('hello').to.equal('hello');
expect(42).to.equal(42);
expect(1).to.not.equal(true);
expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });
expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
Now that you are familiar with the basics of testing write a few more tests for your functions. Here is an example of basic testing covereage:
var expect = require('chai').expect;
var randomNameGenerator = require('./index');


describe('tests should be running', function () {
    describe('list()', function () {
        it('should be an array of strings', function () {
            expect(randomNameGenerator.list()).to.satisfy(isArrayOfStrings);

            function isArrayOfStrings(array) {
                return array.every(function(item){
                    return typeof item === 'string';
                })
            }
        });

        it('should contain `FirstName MiddleName LastName`', function () {
            expect(randomNameGenerator.list()).to.include('FirstName MiddleName LastName');
        });
    });

    describe('single()', function () {
        it('should be a string', function () {
            expect(randomNameGenerator.single()).to.be.a('string');
        });

        it('should contain three names', function () {
            var arrayOfName = randomNameGenerator.single().split(' ');
            expect(arrayOfName).to.have.lengthOf(3);
        });
    });

    describe('startsWithLetter()', function () {
        it('should be a string', function () {
            expect(randomNameGenerator.startsWithLetter('A', 'C', 'E')).to.be.a('string');
        });

        it('should contain three names', function () {
            var arrayOfName = randomNameGenerator.startsWithLetter('A', 'C', 'E').split(' ');
            expect(arrayOfName).to.have.lengthOf(3);
        });

        it('should start with the passed values for f,m,l of A, C, E', function () {
            var arrayOfName = randomNameGenerator.startsWithLetter('A', 'C', 'E').split(' ');
            expect(arrayOfName[0][0]).to.equal('A');
            expect(arrayOfName[1][0]).to.equal('C');
            expect(arrayOfName[2][0]).to.equal('E');
        })
    });

    describe('numberOfNames()', function () {
        it('numberOfNames(3) should have a length of three', function () {
            var arrayOfNames =  randomNameGenerator.numberOfNames(3);
            expect(arrayOfNames).to.have.lengthOf(3);

        });

        it('numberOfNames() should default to one', function () {
            var arrayOfOneName = randomNameGenerator.numberOfNames();
            expect(arrayOfOneName).to.have.lengthOf(1);
        });
    });

});

Now that we have some basic tests we will create a script to run them. Open package.json and in the scripts section we will change the test to:

"test": "mocha src/index.test.js -w"

The -w watches the file system for changes and re-runs the test. There are many more options head to mochajs.org and search for usage:

There we go, we have set up a basic testing framework!

Next… Automating releases

Key:

glyphicons-55-clock  = Time Saving Idea

glyphicons-499-sunglasses = Pro Tip

glyphicons-31-pencil = Note

glyphicons-197-exclamation-sign = Alert

glyphicons-424-git-create = Code Update

glyphicons-28-search  = A Closer Look

Publishing an NPM Module Part 2

These are my notes based on the phenomenal tutorial by Kent C. Dodds hosted by egghead.io both of which are my go to sources when I want to learn something new. I highly suggest you sign up for the pro subscription.

Part 1 | >Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

Part 2: Creating the library

If you missed it check out Part 1: The Setup

This is going to be a tough section. I will be using my module as an example but you will need to create your own. I was inspired by the original tutorial on egghead.io that I can’t recommend enough! Kent C. Dodds is absolutely fantastic. I have a cousin who is an author and one of her issues was coming up with names so I created my random-character-name module to help her out.

The initial step is the same, at the console inside your projects directory type:

$ touch src/index.js

For mine I am also going to use another library in mine called unique-random-array. I also created a data directory to hold my first, middle and last name json objects.

$ npm i -S unique-random-array

glyphicons-499-sunglasses  npm i -S is equivalent to npm install –save

Here is the inital code for my project.

var uniqueRandomArray = require('unique-random-array');
var _ = require('lodash');

//define available data
var firstNames = require('../data/first-names.json');
var middleNames = ('../data/middle-names.json');
var lastNames = ('../data/last-names.json';

//random generators
var randomFirstName = uniqueRandomArray(firstNames);
var randomMiddleName = uniqueRandomArray(middleNames);
var randomLastName = uniqueRandomArray(lastNames);

//filter functions
var filteredNames = function (nameList, initial) {
    return nameList.filter(function (name) {
        return name[0] === initial;
    })
};

module.exports = {
    list: list,
    single: single,
    numberOfNames: numberOfNames
}

//available methods
function list() {
    var allNames = ["FirstName MiddleName LastName"];
    for (var i = 0; i < firstNames.length; i++) {
        var tmpName = randomFirstName() + ' ' + randomMiddleName() + ' ' + randomLastName();
        allNames.push(tmpName);
    }
    return allNames;
}

function single() {
    return randomFirstName() + ' ' + randomMiddleName() + ' ' + randomLastName();

}

function numberOfNames(number) {
    if (number === undefined) {
        number = 1;
    }
    var allNames = [];
    for (var i = 0; i < number; i++) {
        //Math.floor((Math.random() * 10) + 1);
        var tmpName = randomFirstName() + ' ' + randomMiddleName() + ' ' + randomLastName();
        allNames.push(tmpName);
    }
    return allNames;
}

Now, just because we have a thing lets commit that thing!

git commit -am “Initial Commit”

Publish to NPM

Now is the exciting part! We will publish to NPM! Head to your friendly console and type:

$ npm publish
$ npm info the-name-of-your-repo

Let’s do a quick test, we will jump to your Desktop and try it out!

$ cd ~/Desktop
$ mkdir npmtest
$ npm init -y
$ npm install the-name-of-your-package

Now anyone with npm installed can install your package! I was giddy the first time this hit me. Since we really have something now so let’s set our version to 1.0.0 on github.

$ git tag 1.0.0
$ git push --tags

glyphicons-28-search   This a great read if you want to take a closer look.

Head to your https://github.com/repo/releases and you will see the version 1.0.0 tag. Also head to https://www.npmjs.com/package/the-name-of-your-package to check it out! You are a contributor now! (send me a link and I will star you)

Releasing a new version

Add a new feature to index.js. Here is an example. We have added a new function to return a name with specific initials.

function startsWithLetter(f, m, l) { 
    var firstName = _.sample(filteredNames(firstNames, f)); 
    var middleName = _.sample(filteredNames(middleNames, m));
    var lastName = _.sample(filteredNames(lastNames, l));
    return firstName + ' ' + middleName + ' ' + lastName; 
}

We also want to make sure we export our new function.

glyphicons-424-git-create
module.exports = {
    list: list,
    single: single,
    startsWithLetter: startsWithLetter,
    numberOfNames: numberOfNames
}

Since this is not a breaking change and is not just a bug fix we will change the middle number.

glyphicons-28-search  Read about semver at http://semver.org/ but a quick rundown is as follows:

major(breaking).minor(non-breaking new feature).patch(bug)

$ git status
$ git diff
$ git add -A
$ git status
$ git commit -m "[feat] add startsWithLetter method."
$ git tag 1.1.0 //set new version
$ git push
$ git push --tags
$ npm publish
$ npm info the-name-of-your-package

Pushing Beta Version

Make a change. Something you are not sure you want in the default download.  I just added a bunch of comments, nothing serious. 

$ git diff
$ git add -A
$ git commit -am "[docs] add verbose documentation in comments"
$ git tag 1.2.0-beta.0
$ get push
$ git push --tags
$ npm publish --tag beta

To install beta

$ npm i the-name-of-your-package@beta

Or a specific version:

$ npm i the-name-of-your-package@1.2.0-beta.0

Next… Setting Up Testing

Key:

glyphicons-55-clock  = Time Saving Idea

glyphicons-499-sunglasses = Pro Tip

glyphicons-31-pencil = Note

glyphicons-197-exclamation-sign = Alert

glyphicons-424-git-create = Code Update

glyphicons-28-search  = A Closer Look

Publishing an NPM Module Part 1

These are my notes based on the phenomenal tutorial by Kent C. Dodds hosted by egghead.io both of which are my go to sources when I want to learn something new. I highly suggest you sign up for the pro subscription.

>Part 1 | Part 2 | Part 3 | Part 4 | Part 5 | Part 6 | Part 7

Part 1 : The Setup

These are my notes based on the phenomenal tutorial by Kent C. Dodds hosted by egghead.io both of which are my go to sources when I want to learn something new. I highly suggest you sign up for the pro subscription. They are focused on a ‘code first’ delivery so you start learning right away. I made these notes to dig a little deeper on some of the topics, but I would not have known where to get started without these two wonderful resources!

I will be using the following icons to denote certain sections.

glyphicons-55-clock  = Time Saving Idea

glyphicons-499-sunglasses = Pro Tip

glyphicons-31-pencil = Note

glyphicons-197-exclamation-sign = Alert

glyphicons-424-git-create = Code Update

glyphicons-28-search  = A Closer Look

Overview

  1. Create the git repo
  2. Create the library
  3. Publish to npm
  4. Create test suites
    1. Karma
    2. Mocha
    3. Chai
  5. Set up continuous Integration
    1. Travis-CI
  6. Add ES6/ES2015
    1. Babel
    2. web pack
  7. Distribute
    1. NPM
    2. GITHUB
    3. UMD

Create the GitHub Repo

First head over to github.com to create your account if you don’t already have one. Next create a new repo. You can skip creating the README.md as we will be making our own in the next few moments. Take note of the url for the repo as we are going to add it in as the origin in the following steps.

$ echo “# Project name” >> README.md
$ git init
$ git add README.md
$ git commit -m "Initial Commit"
$ git remote add origin <git url> //i.e. https://github.com/jmichelin/something.git
$ git push -u origin master

Setting up NPM

Install Node

To verify that you have node installed run:

$ npm -v

Head to https://docs.npmjs.com/ and read about init-author.name, init-author-email, init-author-url, init-license and save-exact. These set up defaults making future projects even easier. The save-exact true makes your project configured with an exact version rather than using npm’s default semver range operator. There are more but these are some of the more common ones that tend not to change between projects. 

glyphicons-55-clock
Run the following commands:

$ npm set init-author-name 'Name' 
$ npm set init-author-email '<your_email>' 
$ npm set init-author -url '<your_website>' 
$ npm set init-license 'MIT'
$ npm set save-exact true //makes sure you use exact versioning

let’s look at npmrc:

$ cat ~/.npmrc

You will see all of the defaults you set above saved there in case you ever want to edit them.

Create npmjs.com account by heading over to npmjs.com and click on sign up.

screen-shot-2016-09-06-at-4-27-30-pm

Then back in your console:

$ npm adduser

enter npmjs account name, password and Email, add user creates an auth token that you should keep private.

$ npm init

Accept default name, version, enter a brief description, entry point is the file that will be looked at when you require(‘module-name’); change the entry point to read src/index.js accept default for test, for github repo, enter some keywords, accept default license, and create package.json.

Next…Creating a Library

glyphicons-499-sunglasses start thinking about what you might want to make and keep it simple.

Added UMD version to NPM Module

I added a browser consumable version of my amazing (to me at least) random-character-name module. Now you can just include the cdn version and you are good to go. It was pretty easy really. I just needed to add a few build scripts to package.json. I installed webpack as a dev dependency and put in the following two scripts:

"build:umd": "webpack --output-filename index.umd.js",
"build:umd.min": "webpack --output-filename index.umd.min.js -p",

You can use it over at https://npmcdn.com/random-character-name@1.6.0/dist/index.umd.js or for the minified version head to  https://npmcdn.com/random-character-name@1.6.0/dist/index.umd.min.js.

Happy random name generating!

My first NPM Module

I finally got around to publishing an NPM module (Thank you Kent C Dodds!) It is pretty simple, but it  solves a problem I have had as a writer. Names! It let’s a user generate a name, an array of names with a given length, a massive list of names or a name with specific Initials.

Simply run the following.

npm i random-character-name

and you are good to go! Head to npm or github if you want to contribute!

The method list() will return a list of all random names that were generated. The method single() will return a single random name. The method startsWithLetter(f,m,l) will let you set the initials. The method numberOfNames(number) will return the requested number of names.

var rndNameGen = require(random-character-name);
 
rndNameGen.list();
//generates a large array of names 
/* 
ex.
  [‘Em Andre Vento’,
  ‘Marsiella Lester Drisko’,
  ‘Lou Charley Hoang’,
  ‘Bettye Ransell Cristabel’,
  …
  ‘Shawnee Timothee Rigby’,
  ‘Roch Wilbur Ithnan’,
  ‘Shanta Wheeler Milicent’,
  ‘Janela Wally Marlowe’ ]
 
*/
 
rndNameGen.single(); 
//generates a string with a random name 
//ex. ‘Donnie Reinhard Levin’ 
 
rndNameGen.startsWithLetter(A,C,E);
//generates a string with a name with requested initials 
//ex. ‘Ajay Christophorus Elset’ 
 
rndNameGen.numberOfNames(3)
//generates an array with the number of names requested. 
/*
ex.
[ ‘Nedi Burt Lexine’,
  ‘Cairistiona Jacobo Merl’,
  ‘Annaliese Bartolomeo Cherian’ ]
*/

Super Useful!

If you are doing a fresh install jump to step three! It will save you the hassle of doing it later. I had to do this to make my travisCI much easier to deal with on different machines.

  1. Find the path to npm’s directory:
     npm config get prefix
    

    For many systems, this will be /usr/local.

    WARNING: If the displayed path is just /usr, switch to Option 2 or you will mess up your permissions.

  2. Change the owner of npm’s directories to the name of the current user (your username!):
     sudo chown -R $(whoami) $(npm config get prefix)/{lib/node_modules,bin,share}
    

    This changes the permissions of the sub-folders used by npm and some other tools (lib/node_modules, bin, and share).

This worked for me but there are other options. On the npm docs site.

Sem.Ver.Blog

It is just Numbers and Dots, right?

I just released a new version of software. I called it 1.0.0. Why did I do that? Really it was because that is just what I do. When I make a very tiny change I adjust the last number up. When I have enough tiny changes that I can bundle them up I adjust the middle number and when I have a significant number of those changes I adjust the first number.

Is this right? No, no it is not. So it’s time to figure this out. Let me go to the source:

(from http://semver.org/)

Summary

Given a version number MAJOR.MINOR.PATCH, increment the:

  1. MAJOR version when you make incompatible API changes,
  2. MINOR version when you add functionality in a backwards-compatible manner, and
  3. PATCH version when you make backwards-compatible bug fixes.

Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.

This makes way more sense. When you make incompatible API changes the major version must change, otherwise it is just extending the current versions functionality (still backwards-compatible) and finally if you are making changes, that don’t add functionality but fix originally intended functionality while maintaining the same backwards-compatibility it is a patch.

Why should I care? Do you want to live in dependency hell? I thought not. The more complicated software gets, the more likely conflicts occur among dependencies and interdependencies.  How do we avoid this? By making sure that when we write a library with a public API we show how it’s used and how it will not be used. Once these restrictions change we know we have to think about bumping up the major version. Those who want to keep their code working can stick with the working major version until they have reviewed potential impact and decide to upgrade or not.

It is not overly complicated, but I highly suggest reading the full spec to become fully enlightened. versioning