Hitchhiker's Guide To Writing Your First Open-source software

This article is written just from my perspective to help out beginners. If you disagree from anything in this piece, I respect that.

Before you start reading this article, let me just stop you right there. Why!? You asked and I obliged. To congratulate you! Confused!? If you have decided to give this piece a go then at some part of your mind you want to take the first step towards open-source and I am really glad that I can contribute to it. 🥂

Well today, I have something special for you. In the past, you might have used packages from one of the biggest open-source package repositories, i.e., npmjs. Today, I am going to teach you just how simple it is to write your own open-source node package and then publish it on npmjs.

Let’s do it in steps to make things simpler.

🏗 STEP #1 – Setting Up Everything

Every good open-source project contains some files that build confidence. For instance, having a code of conduct, contributing guidelines, and proper documentation goes a long way. Plus, don’t forget the license while we are talking about such files.

Since I have some experience myself writing open-source automation tools and packages, I decided to save you some time and cooked up something that you could use to get started with everything using a single command. But before I tell you about that, let’s create a folder called cross-path.

cross-path is going to be an npm package that will convert darwin paths to win32 and win32 paths to darwin.

Navigate inside this folder and type the following in the terminal:

npx create-foss-files --javascript

This is going to go ahead and set up everything you need for an open-source project.

Just so you know, I have also written a piece about the files you should have in an open-source project if you want to read it.

Once you are done, open this folder in your VSCode or preferred code editor and write your contributing guidelines in the contributing.md file.

🎩 STEP #2 – Writing Your Package Metadata

The files that have just been created would contain a package.json file. Safe to say that this file contains all the metadata of your project. Open it.

You will see many empty fields inside of it. Fill them one by one. Give your package a name, description, version, etc. Since I am writing a package to generate cross-platform paths, I am going to give it the name cross-path, some description to explain the functionality of the package, and fill out other stuff as well.

The file will look something like this:

{
    "name": "cross-paths",
    "version": "1.0.0",
    "description": "Converts paths from darwin to win32 platform and vice versa",
    "repository": "https://github.com/msaaddev/cross-paths",
    "author": {
        "name": "Saad Irfan",
        "email": "[email protected]",
        "url": "https://twitter.com/msaaddev"
    },
    "main": "index.js",
    "license": "MIT",
    "scripts": {
        "format": "prettier --write \"./**/*.{js,json}\"",
    },
    "keywords": [
        "cross paths",
        "windows to unix paths",
        "unix to windows path",
        "darwin to windows path",
        "windows to darwin path",
        "path converter",
        "convert paths",
        "Saad Irfan",
        "msaaddev"
    ],
    "devDependencies": {
        "prettier": "^2.3.2"
    },
}

Make sure to give your package appropriate keywords related to the package you are building so people can find your package on npmjs.

💻 STEP #3 – Coding

The next step is to write the magic which some people also call code. Open the index.js file for this. I am not going to waste your time with this part of the process since it varies from package to package.

Although, I am still sharing the code of this cross-path package.

/**
 *
 * Author: Saad Irfan
 * GitHub: msaaddev
 * Twitter: https://twitter.com/msaaddev
 */

const logSymbols = require('log-symbols');
const nodePath = require('path');
const { toUnix } = require('upath');

/**
 *
 *
 * @param {path} - darwin path
 * @returns {path} - win32 path
 */
const darwinToWin32 = path => {
    if (!path) {
        console.log(`${logSymbols.error} Please provide a valid path`);
        return null;
    }
    return nodePath.win32.normalize(path);
};

/**
 *
 *
 * @param {path} - win32 path
 * @returns {path} - darwin path
 */
const win32ToDarwin = path => {
    if (!path) {
        console.log(`${logSymbols.error} Please provide a valid path`);
        return null;
    }
    return toUnix(path);
};

module.exports = {
    darwinToWin32,
    win32ToDarwin
};

There is one extremely important thing which I need to explain to you. You need to know what module.exports does.

‼️ module.exports exports anything you set equal to it. You can export anything (variable, object, arrays, functions, classes) from a file through this and it will export it as a module. If you look at the code above, you will notice that I am exporting an object through module.exports. The object contains two functions. So in turn, I am exporting two functions from this file via an object.

Make sure the function/s that you want other people to use via your package must be put inside of this object. I recommend you read this article to get a better understanding of module.exports.

You can use module.exports to modularize your code across multiple files. This will help the readability of your codebase.

Every module that you export can be imported in another file using the require keyword. ⚡️

I don’t know if you have noticed but I am using three other packages in the code above. I am importing it into my index.js file using the require keyword. Just so you know, this is how someone is going to use your code in their project.

📖 STEP #4 – Documentation

Once you are done coding your package, be sure to write a good documentation so people can actually use your package. The documentation plays a vital part in the success of any project.

For this purpose, open readme.md file and write things like features, installation guide, usage, any other information that you think is important, etc.

🎯 STEP #5 – Sign Up And Login

Before you can publish your package, you need to first sign up on npmjs.com. So go ahead and do this.

When you are done, open your terminal and type the following command there:

npm login

You will asked a bunch of questions like your username, email, password, etc. Answer them one by one. Now your computer terminal is connected with your npmjs account.

🚀 STEP #6 – Publishing

The last thing you need now is to publish your package on npmjs. For this, all you need to do is open your project terminal, and type the following there:

npm publish

This command is going to go ahead and publish your project. And that’s all. You have successfully published your first open-source software on one of the biggest platforms out there.

⚠️ Common Errors

This post can’t be completed with me telling you some of the common errors that you might see while publishing your open-source package.

Sometimes when you try to publish your package, you run into an error. It can be due to any of these two reasons:

  • A package with the same name already exists. In this case, either you need to change the name of your package or make a scoped package. Read more about scoped package here.

  • You have not updated the version number of your package before publishing it again. Everytime you have made a change and now you are publishing your package again, you would need to change its version. It is because you can not publish again on an existing version. I would suggest following semantic versioning.

I know I have not talked about writing tests. It is because I have tried to make this piece as beginner oriented as possible.

I think every developer is a magician who can produce magic via a few strokes of the keyboard (maybe not a few but you get the idea). I have also tried making a bit of a magic myself. One of them is the new-tailwind-app that can get you started with Tailwind integrated web app with a single command. You can see more of my projects here. Be sure to follow me while you are at it. 🙌🏻

Cheerios 🤞🏻

23