Codementor Events

How to Create and Publish an npm module in TypeScript

Published Oct 27, 2017Last updated Apr 25, 2018
How to Create and Publish an npm module in TypeScript

Introduction

In this article, we are going to see how we can build a module with TypeScript that both JavaScript developers and TypeScript developers can use.

Most npm modules come without a Type definition, so TypeScript developers will have to run an additional npm i @types/<module_name> -D command to be able to use the npm module. Here, we will see how to create an npm module in TypeScript “importable” in JavaScript and TypeScript.

What is npm?

npm is an online registry for open-source node.js projects, modules, resources, etc. You can find it at http://npmjs.org.

npm is the official package manager for node.js and provides a command line interface (CLI) for interacting with the registry. This utility comes bundled with node.js and is installed automatically. For API documentation, visit https://npmjs.org/doc/ or just type npm in your terminal.

Installing Node.js

Head to the Node.js download page and grab the version you need. There are Windows and Mac installers available, as well as pre-compiled Linux binaries and source code. For Linux, you can also install Node via the package manager, as outlined here.

Let’s see where node was installed and check the version.

node -v
v6.10.0

The Node.js installation worked, so we can now focus our attention on npm, which was included in the install.

npm -v
3.10.10

Node.js Module

Module in Node.js is a simple or complex functionality organized in single or multiple JavaScript files, which can be reused throughout the Node.js application.

Each module in Node.js has its own context, so it cannot interfere with other modules or pollute the global scope. Also, each module can be placed in a separate .js file under a separate folder.

Node.js implements CommonJS modules standard. CommonJS is a group of volunteers who define JavaScript standards for web server, desktop, and console applications.

Let’s build a module that returns the plural form of any noun.

Create a GitHub repo

  1. Create a new repo on GitHub and call it mypluralize (make sure you check the README box, add a . gitignore file for Node, and a MIT license)
  2. Clone it locally
git clone https://github.com/philipszdavido/mypluralize.git

Initialize a npm package

When you create a new module, you want to describe your package with the package.json file.

npm init

This command will ask you some questions to generate a package.jsonfile in your project route that describes all the dependencies of your project. This file will be updated when adding further dependencies during the development process, for example, when you set up your build system.

name: (project-name) project-name
version: (0.0.0) 0.0.1
description: The Project Description
entry point: //leave emptytest 
command: //leave empty
git repository: //the repositories url
keywords: //leave empty
author: // your name
license: N/A

After you’ve finished the process of initializing your project using the Node Package Manager, node.js created a package.jsonfile in your project's root directory similar to this one:

{ "name": "project-name", "version": "0.0.1", "description": "Project Description", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "repository": { "type": "git", "url": "the repositories url" }, "author": "your name", "license": "N/A"}

If you want to skip the above questions, you can use

npm init -y

It will use only defaults and not prompt you for any options.

Set Your npm Defaults

npm set init.author.name “Chidume Nnamdi”
npm set init.author.email “kurtwanger40@gmail.com”
npm set init.author.url “http://twitter.com/ngArchangel"

Your credentials will be now saved to a ~/.npmrc file and used as defaults whenever you initialize a npm package, so you don’t have to enter them each time.

Installing Dependencies

Now that you have a working Node project, move into the folder

cd mypluralize

Our package.json, should look like this.

{ "name": "mypluralize", "version": "1.0.1", "description": "A Node.js module that returns the plural form of any noun", "main": "index.js", "repository": { "type": "git", "url": "git+https://github.com/philipszdavido/mypluralize.git" }, "keywords": [], "author": "Chidume Nnamdi <kurtwanger40@gmail.com>", "license": "ISC", "bugs": { "url": "https://github.com/philipszdavido/mypluralize/issues" }, "homepage":"https://github.com/philipszdavido/mypluralize#readme"}

Install TypeScript

Next, let us install TypeScript

npm i typescript -D

Configure our tsconfig file

Next, we'll create the tsconfig.json file. The presence of a tsconfig.json file in a directory indicates that the directory is the root of a TypeScript project. The tsconfig.json file specifies the root files and the compiler options required to compile the project.

You can create the file manually, then make it look like this.

{ "compilerOptions": { "target": "es5", "module": "commonjs", "declaration": true, "outDir": "./dist", "strict": true }}

You can generate the tsconfig.json file automatically using the tsc — init. To be able to use tsc globally, run the commands

npm i -g typescript -Dnpm i -g typings -D

Then, generate the tsconfig.json

tsc --init

If you don’t have TypeScript installed globally in your system, our previous command

npm i typescript -D

installed tsc locally in the node_modules folder, so we can reference the file path

./node_modules/.bin/tsc --init

We can just use tsc --init because tsc has a cmd in the node_modules/.bin folder.

Now, if you used this method, make sure your generated tsconfig.json looks like this

{ "compilerOptions": { "target": "es5", "module": "commonjs", "declaration": true, "outDir": "./dist", "strict": true }}

“target”: “es5” => Specify ECMAScript target version: ‘ES3’ (default), ‘ES5’, ‘ES2015’, ‘ES2016’, ‘ES2017’, or ‘ESNEXT’.> “module”: “commonjs” => Specify module code generation: ‘none’, commonjs’, ‘amd’, ‘system’, ‘umd’, ‘es2015’, or ‘ESNext’.> “declaration”: true => Generates corresponding ‘.d.ts’ file.> “outDir”: “ dist” => Redirect output structure to the directory.

Writing our Node module

Create a lib folder and a index.ts file inside of it.

mkdir lib && touch index.ts

Add the following code to your index.ts. Before that, we will need the help of an npm module pluralize, so let's pull it into the show.

npm i pluralize -S

index.ts

import * as pluralize from 'pluralize'
/*** @Method: Returns the plural form of any noun.* @Param {string}* @Return {string}*/export function getPlural (str: any) : string { return pluralize.plural(str)}

Notice, our IDE (VS Code, Atom, Sublime Text) will signal a type error here.

import * as pluralize from 'pluralize
'Could not find a declaration file for module ‘pluralize’.

This is because the pluralize module doesn’t have a ‘.d.ts’ file. To fix this issue, we run this command.

npm i @types/pluralize -D

These pull the definition files and place it in the @types folder in our node_modules folder. You’ll notice that after pulling in the definition files, the errors are gone.

Building our project

We will modify our package.json to include script that builds our code.

{ "name": "mypluralize", "version": "1.0.1", "description": "A Node.js module that returns the plural form of any noun", "main": "index.js", "scripts": { "build": "tsc" }, "repository": { "type": "git", "url": "git+https://github.com/philipszdavido/mypluralize.git" }, "keywords": [], "author": "Chidume Nnamdi <kurtwanger40@gmail.com>", "license": "ISC", "bugs": { "url": "https://github.com/philipszdavido/mypluralize/issues" }, "homepage":"https://github.com/philipszdavido/mypluralize#readme" , "devDependencies": { "typescript": "^2.5.3" }, "dependencies": { "@types/pluralize": "0.0.27", "pluralize": "^7.0.0" }}

We can run

npm run build

Voila! Our code is now compiled to JavaScript!! A new dist directory is created with index.js and index.d.ts files in it. The index.js contains all the logic that we coded, compiled to JavaScript, and index.d.ts is the file that describes the types of our module for use in TypeScript. Lets make some changes to our package.json file.

Change the main attribute to point to ‘dist/index.js’>. Create a ‘types’ attribute and set the value to ‘dist/index.d.ts’.

{ "name": "mypluralize", "version": "1.0.1", "description": "A Node.js module that returns the plural form of any noun", "main": "dist/index.js", "types" : "dist/index.d.ts", "scripts": { "build": "tsc" }, "repository": { "type": "git", "url": "git+https://github.com/philipszdavido/mypluralize.git" }, "keywords": [], "author": "Chidume Nnamdi <kurtwanger40@gmail.com>", "license": "ISC", "bugs": { "url": "https://github.com/philipszdavido/mypluralize/issues" }, "homepage":"https://github.com/philipszdavido/mypluralize#readme" , "devDependencies": { "typescript": "^2.5.3" }, "dependencies": { "@types/pluralize": "0.0.27", "pluralize": "^7.0.0" }}

Write some tests

We are going to use the Mocha testing framework and Chai assertion library.

npm i mocha -Dnpm i chai -D

Create a test folder and test.js file in it.

mkdir test && touch test/test.js

test.js

'use strict';var expect = require('chai').expect;var index = require('../dist/index.js');
describe('getPlural function test', () => { it('should return Boys', () => { var result = index.getPlural('Boy'); expect(result).to.equal('Boys'); }); it('should return Girls', () => { var result = index.getPlural('Girl'); expect(result).to.equal('Girls'); }); it('should return Geese', () => { var result = index.getPlural('Goose'); expect(result).to.equal('Geese'); }); it('should return Toys', () => { var result = index.getPlural('Toy'); expect(result).to.equal('Toys'); }); it('should return Men', () => { var result = index.getPlural('Man'); expect(result).to.equal('Men'); });});

Run our tests

Add a test script to our package.json.

"scripts": { "build": "tsc", "test": "mocha --reporter spec"}

Let’s run our test script.

npm run test


Mocha test run

Write our readme

# mypluralizeA Node.js module that returns the plural form of any noun

Installation

shnpm install mypluralize --saveyarn add mypluralizebower install pluralize --save```

JavaScript

javascriptvar pluralise = require('mypluralize');var boys = pluralise.getPlural('Boy');``````shOutput should be 'Boys'```

TypeScript

typescriptimport { getPlural } from 'mypluralize';console.log(getPlural('Goose'))``````shOutput should be 'Geese'```

AMD

javascriptdefine(function(require,exports,module){ var pluralise = require('mypluralize');});```

Test

shnpm run test

Commit and push to Git

git add .
git commit -m “Initial release”
git tag v1.0.1
git push origin master --tags

Publish to npm

Before we publish our code, there are some unnecessary folders and files to exclude from the installation of our module. The lib folder shouldn’t be published. Create a .npmignore file and add the following contents

.npmignore
lib/

We are set to publish our module. Run the command:

npm publish

Note

  • Make sure that there isn’t already a package with the same name.

To publish, you must be a user on the npm registry. If you don’t have one, create it with npm adduser. If you created one on the site, use npm login to store the credentials on the client.

Test: Use npm config ls to ensure that the credentials are stored on your client. Check that it has been added to the registry by going to https://npmjs.com/~.

If everything went well, you will see something like this in your cmd.


npm publish success

Adding Continuous Integration

We will be using Travis CI for our continuous integration. Follow the steps below to integrate Travis CI to your project.

  1. Navigate to Travis CI.


Travis CI

  1. Click on ‘Sign in with GitHub’.

  1. Flick the repository switch on.

  1. Add .travis.yml to your repo.
language : node_jsnode_js : - stableinstall: - npm installscript: - npm test
  1. Commit and push to git.

Pushing to git will trigger your first build. Log in to Travis to see your build status.

Add Coverage Data

Coveralls is a hosted analysis tool that provides statistics about your code coverage. Coveralls is a web service to help you track your code coverage over time and ensure that all your new code is fully covered.

There is but one prerequisite for Coveralls Cloud (Coveralls Enterprise can use a variety of repo-hosting options):

The Coveralls service is language-agnostic and CI-agnostic, but we haven’t yet built easy solutions for all the possibilities as far as repo hosting. Creating an account is fast and easy, just click the “Sign in” button for your git service (you can link accounts later) and authorize Coveralls to access your repos — no forms to fill out.

Log in to Coveralls with your GitHub account, click the “ADD REPO ” button, and toggle the switch to enable the repo for which you want code coverage statistics.

Get code coverage with Istanbul

There are many tools to analyze code coverage, but I find Istanbul simple and effective, so that’s what we’ll use here.

First, install Istanbul and coveralls as a devDependency:

npm i istanbul -Dnpm i coveralls -D

We’ll make an npm run for our code coverage. Here’s the script we’ll add:

"cover": "istanbul cover node_modules/mocha/bin/_mocha test/*.js - - -R spec"

So now your package.json should have both scripts:

"scripts": { "test": "mocha --reporter spec", "cover": "istanbul cover node_modules/mocha/bin/_mocha test/*.js -- -R spec" },

Update your .travis.yml file to this

language : node_js
node_js : - stable
install: - npm install
script: - npm run cover
# Send coverage data to Coverallsafter_script: "cat coverage/lcov.info | node_modules/coveralls/bin/coveralls.js"

Now you can run your tests and code coverage stats from your command line with

npm run cover

Now, commit and push to GitHub.

Travis will now invoke Istanbul, and Istanbul will run an lcovonly code coverage report. Save that info to coverage/lcov.info, and pipe that data to the Coveralls library.

Log in to Coveralls to check and see if everything executed smoothly.

Adding some badges

Let's get them on our Git and npm repos.

Travis

Click on the settings toggle next to your repo on Travis CI, and click on the badge icon.

Choose Markdown and add the code to your README.

Coveralls

Log in to Coveralls, click on your repo, click the “ BADGE URLS ” dropdown, and add the Markdown code to your README.

Commit and push to GitHub.

Travis will run your tests, and you can see your build status in your GitHub README.

We need to get them on npm. To do that, we are going to release a new version. That is the only way to push your changes to npm.

npm version patch -m "Version %s - add sweet badges"

%s = the new version number.

This command will bump the version number in package.json , add a new commit, and tag it with this release number.

Note : Your Git working directory has to be clean before you can run npm version.

After bumping the version number,

git push && git push --tags (or git push origin master --tags)
npm publish

Now, if you go to your published module on npm, you should see your new release with the two sweet badges!

Conclusion

We have succeeded in writing and publishing an npm module in TypeScript. The great thing that we achieved here is that our module can now be seamlessly used in JavaScript or TypeScript projects without any need to run:

npm i @types/mypluralize -D

Feel free to reach out if you have any problems.

Code in Github

Special thanks to

  • Joanne for giving me an insight into Continuous Integration.
  • Rowland Ekemezie for showing and guiding me on how to become a professional writer/developer.
  • Grammarly.com for proof-reading.

Follow me on Medium and Twitter to read more about TypeScript, JavaScript and Angular.

Discover and read more posts from Chidume Nnamdi
get started