Ionică Bizău

Web Developer, Linux geek and Musician

How I npm

I write a lot of code every day, publishing my code on GitHub and npm. Each tiny package I create does something, and in most of the cases it's a module which can be used in other applications. :four_leaf_clover:

:thought_balloon: What is npm?

In case you don't know, npm is the default package manager for Node.js. Note that there we can publish modules which are not Node.js specific.

Its name stands for need pray more (or nuclear pizza machine, or npm's pretty magical etc etc).

Whaaat?!

Well, if you are here and think that npm stands for Node Package Manager, I have to tell you that's also correct, but it's not complete. npm is not an acronym, but it's a recursive bacronym for npm is not an acronym. In short, npm is an bacronym, not an acronym like many people believe.

You can refer to npm/npm-expansions for a list of things npm stands for. :sparkles:

At this very moment while writing this post, I currently have 561 packages. You can view them here (npm/~ionicabizau).

:raised_hands: How I do it

I started learning Node.js at the end of the year 2012. I was enjoying using modules by others, but I published my first npm package in August 2013. It was youtube-api–a friendly Node.js wrapper for the YouTube API. :tv:

I liked the npm publishing workflow and I didn't stop there. I created more and more packages.

:rocket: How to create an npm package?

Assuming you have Node.js and npm installed, you have to generate a package.json file then write your code and publish it:

# Generate the package.json file
npm init

# Work on your magic
echo 'module.exports = 42' > index.js

# Publish the stuff
npm publish

But a good package should include good documentation as well as easy to use APIs and easy examples.

:crystal_ball: Automatization and Magic

From publishing new stuff on npm, I found that I was doing a bit of manual work every time. That included:

  1. Creating GitHub repositories
  2. Creating releases on GitHub
  3. Maintaing documentation in sync with the code
  4. Maintaining the same documentation format across the repositories

I started to analyze where I wasted time and created small tools to do the work for me. :construction_worker:

:memo: Blah: Fancy Documentation

I created a tool called blah which, since 2014, takes care of generating the documentation for me:

  • It generates README.md files based on my templates.
  • Handles custom stuff by looking at the blah field in package.json
  • Generates documentation by looking at the JSDoc comments from my code.
  • Bumps the package.json version
  • Creates the CONTRIBUTING.md, LICENSE (takes care of updating the year as well!), .travis.yml and .gitignore files

Pretty cool. Since then I didn't have to manually write Markdown files anymore.

:page_with_curl: Packy: package.json defaults

Every time you npm init a package, you have to write stuff like the author, git repository, license etc.

I created packy which takes static (e.g. author) and dynamic (e.g. git repository url) fields by looking at a configuration file.

After this, I was manually writing the name and description fields and then skipping the others. Then, I ran packy which was autocompleting the author, keywords, git-related stuff and so on.

Since blah can run custom commands for me, I decided to integrate packy in my blah configuration.

:tophat: np-init: Automagically create new packages

Because I was still lazy to create the files manually, I created np-init which creates a minimal npm module:

np-init my-super-package-name 'Some fancy description'

Then I just have to cd my-super-package-name and work on my code directly because everything is there for me (example/index.js, lib/index.js, package.json etc).

:dizzy: babel-it: Babelify the things

Because I started to use ES2015 features in my code and since many people use versions of Node.js which do not support ES2015, I started publishing transpilled versions of my code on npm.

After building babel-it, I replaced the npm publish command with babel-it! That is smart enough to babelify my code, publish it on npm and then rollback to my original code.

:ship: Ship Release

The publishing process was boring again. I decided to create a tool to take care of that: ship-release.

So that being said, I don't even need to take care of babelifying the things because ship-release does that (using babel-it).

After fixing a bug into a package, I simply do:

# Creates and switches on the new-version branch
ship-release branch -m 'Fixed some nasty bug'

# Bump the version
ship-release bump

# Publish
#  - generate docs using Blah
#  - push the changes on GitHub
#  - create and merge the pull request
#  - create a new release in the GitHub repository
#  - transpile the code
#  - publish the new version on npm
ship-release publish -d 'Fixed some nasty bug.'

That's the theory. Let's see all these running in the real world.

Example

Today I'm creating a small module called stream-data which will collect the data emitted by a stream and send it into a callback.

Creating the package

As mentioned above, I'm using np-init to do that:

np-init stream-data 'Collect the stream data and send it into a callback function.'

This created the following directory:

stream-data/
├── (.git)
├── example
│   └── index.js
├── lib
│   └── index.js
└── package.json

2 directories, 3 files

Write a minimal example

When building a house, you have to start with the base. When building an npm package, I like to start with the roof.

Even if the library doesn't do anything yet, I just set up an example the way I'm thinking I want the module to work.

So, I cd stream-data and write this (note that I already had something there created by np-init):

"use strict";

const streamData = require("../lib")
    , fs = require("fs")
    ;

// Create a read stream
let str = fs.createReadStream(`${__dirname}/input.txt`);

// Pass the stream object and a callback function
streamData(str, (err, data) => {
    console.log(err || data);
    // => "Hello World"
});

Write the functionality in the library

np-init generated a JSDoc comment, which initially looked like this:

/**
 * streamData
 * Collect the stream data and send it into a callback function.
 *
 * @name streamData
 * @function
 * @param {Number} a Param descrpition.
 * @param {Number} b Param descrpition.
 * @return {Number} Return description.
 */

I slightly changed the function parameters' names and updated the JSDoc comment:

"use strict";

/**
 * streamData
 * Collect the stream data and send it into a callback function.
 *
 * @name streamData
 * @function
 * @param {Stream} str The stream object.
 * @param {Function} cb The callback function.
 * @returns {Stream} The stream object.
 */
module.exports = function streamData (str, cb) {

    if (cb) {
        let buffer = []
          , error = null
          ;

        str.on("data", chunk => buffer.push(chunk));
        str.on("error", err => error = err);
        str.on("end", () => cb(error, buffer.join(""), buffer));
    }

    return str;
};

Run the example

Well, now we can see if it's really working.

$ node example/
Hello World!

Before publishing it, we need to set up some tests.

Tests

For testing I use tester. To add tester in my project I do tester-init.

$ tester-init
...
$ tree
...
└── test
    └── index.js

After writing a few tests, the module is ready to be published on GitHub and npm.

Publishing

We have to create a GitHub repository. I use ghrepo by @mattdesl (thanks! :cake: :grin:). It's smart enough to create the GitHub repository with the right data (taken from the local git repository url and package.json).

ghrepo --bare --no-open
ship-release bump
ship-release publish -d 'Initial release'

Looking in my directory now, I have a couple of new files (README.md, CONTRIBUTING.md, .gitignore etc).

Now my module is on GitHub and npm ready to be npm installed:

// After doing: `npm install --save stream-data`

const streamData = require("stream-data")
    , fs = require("fs")
    ;

// Create a read stream
let str = fs.createReadStream(`${__dirname}/input.txt`);

// Pass the stream object and a callback function
streamData(str, (err, data) => {
    console.log(err || data);
});

:mortar_board: Things I learned

Do not do manual work. Optimize things as much as you can. Otherwise, you'll waste your precious time. Create your team of bots to help you to optimize things.

Happy npming! :tada:


If you like to support what I do, here is how you can do it.

Read more »

What to Do When Your Website is Broken

Our job as developers is to break and fix stuff every day. Sometimes, some of us even do it on production servers. But during emergencies, they just tend to apply a quick fix which may not actually fix anything at all— in fact, it could even make things worse.

On some days, it works! But it's still very dangerous:

website is broken
This is a good example of fixing a bug on production with a happy ending. [source]

These things happen. But when they do, how can we address these issues with confidence and in the best way possible?

In this this article I will show you 7 general steps to fix your website, application, or code when it's broken.

1. Don't panic. Relax.

We are all humans. We make mistakes. When something gets broken, don't contribute to the mess by panicking. Try to settle down first before you do anything with it. Try drinking a glass of water and relax while trying to figure what's going on. Remember, think first before you code!

2. Reproduce the problem. Then reproduce it locally.

Let's suppose the website you're having a problem with is on production and users start complaining about a specific functionality.

Doesn't work is not enough. Ask your users to define what doesn't work means. Is there an error? What are the issue reproduction steps? Is it happening always?

Can you reproduce the bug on the production website? If yes, then try to reproduce it locally (or in your development environment). If you do this, however, you should be prepared to debug it. If you can't reproduce it locally, check out the machine-specific settings/resources. Here are few:

  • Database content: Maybe the bug appears only at a specific document that exists on production, but you don't have it locally.
  • Environment configuration: Maybe there are some environment variable or setting you need to change.
  • Make sure you're in sync with the production server code (including dependencies' versions).

But it's working on my machine!

Well, if you can't reproduce it on production, there is a high chance that it's a browser-specific issue. For example, maybe you used a function that doesn't exist on some old version of Internet Explorer, or maybe you shipped your ES2015 code directly, without transpiling it to ES5. In that case, if it's still unclear what's going on, ask for more information: Where does the issue appear? What operating system and what browser (including their versions) are they using?

If you're using the same OS and browser versions, ask them to clear the browser cache then retry. Also, you should also clear your own browser cache and retry.

Oh, yeah! Typos!

Before starting to reproduce the issue and debugging the actual code, make sure your input data is correct. You can't expect correct output if your input is incorrect (duh?).

Sometimes just by staring a bit at the code/urls/input content, you can easily fix things. As developers, we often waste lot of time debugging stuff which looks correct but turns out to be a typos in the end. And then we are like:

website is broken
After wasting a lot of time trying to fix a typo.

So, pay attention to typos. They are funny to fix, but developers often forget to think that well, maybe it's just a typo.

Read the full article on CodeMentor »

Read more »

The Amazing Tangram Square

I was 7 years old when I first found out what the Tangram Square is. I saw it in a Maths book and I quickly started to have fun with it.:dizzy:

The Tangram is a Chinese geometrical puzzle consisting of a square cut into seven pieces:

  • 2 large right triangles
  • 1 medium right triangle
  • 2 small right triangles
  • 1 square
  • 1 parallelogram

These pieces can be used to create different shapes (animals, objects etc).

Recently I thought that it's not a bad idea to to bring this game on the WEB, so anybody can play it.

And I did it! You can play it here. :sparkles:

Using svg.js and a bit of math I created the pieces. To make them interactive, I set up the mouse-related events (click, drag etc):

  • Left click: rotate left
  • Right click: rotate right
  • CTRL + left click: flip
  • Hold left click + move: drag

You can build pretty much anything. From hearts... :sparkling_heart:

...to cats :heart_eyes_cat:...

...and a lot of other shapes. Then, once you got it, be creative and create your own stuff.

The source code is hosted on GitHub. Hope you'll enjoy playing this game! :grin:

Read more »