How to create and publish a typescript module on npmjs.com

raphaelmansuy

Raphael MANSUY

Posted on September 6, 2020

How to create and publish a typescript module on npmjs.com

This tutorial explains

  • How to configure a typescript package from zero
  • How to add the support of Jest for the unit tests
  • How to generate the tests coverage
  • How to publish the library in npmjs.com

Let's create a simple library to validate emails and IPv4 addresses. The name of this library will be xanthe.

️Xanthe means “golden” or “yellow” in Greek. Xanthe is an exotic epithet of Demeter, goddess of the harvest and agriculture 🇬🇷🧚‍♀

Create a package.json file

{
  "name": "xanthe",
  "version": "0.0.1",
  "author": {
    "email": "contact@elitizon.com",
    "name": "elitizon"
  },
  "license": "MIT",
  "description": "A library to validate common formats such as emails, numbers, phone numbers, and IP addresses",
  "contributors": [
    "raphaelmansuy"
  ],
  "keywords": [
    "format",
    "validator",
    "email validation",
    "IP address validation"
  ],
  "dependencies": {},
  "devDependencies": {}
}

Enter fullscreen mode Exit fullscreen mode

Install typescript as a development dependencies

yarn add -D typescript @types/node
Enter fullscreen mode Exit fullscreen mode

@types/node contains type definitions for Node.js
typescript contains the typescript compiler

Create the src and test directory

mkdir src
Enter fullscreen mode Exit fullscreen mode
mkdir tests
Enter fullscreen mode Exit fullscreen mode

Install a testing environment

Install Jest as a development dependency

Jest is a testing library developed by Facebook.

yarn add -D jest ts-jest
Enter fullscreen mode Exit fullscreen mode

Create a jest.config.js file to configure Jest

module.exports = {
  transform: {'^.+\\.ts?$': 'ts-jest'},
  testEnvironment: 'node',
  testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
}
Enter fullscreen mode Exit fullscreen mode
  • All the files ending by .ts will be handled by ts-jest.
  • The test environment is nodejs
  • The test files are contained in the ./tests directory and must have .test. or .spec. in the filename and must end by .ts or .tsx

Create a script section in the package.json file

  "scripts": {
    "build": "tsc",
    "test": "yarn build && jest",
    "coverage": "jest --coverage"
  },
Enter fullscreen mode Exit fullscreen mode
  • build: invoke the typescript transpiler
  • test: build and invoke the tests
  • coverage: generate the tests coverage in the coverage directory

Create a tsconfig.json file to configure typescript

{
  "compilerOptions": {
    "target": "es5" ,
    "module": "commonjs",
    "outDir": "./build",
    "strict": true,
    "esModuleInterop": true ,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "declaration": true
  },
  "exclude": ["node_modules", "build", "tests"]
}
Enter fullscreen mode Exit fullscreen mode

The build command will generate the CommonJS files in the ./build/ directory

Creation of validations functions

Create a file email.ts in ./src/validators/ directory


/**
 * @param email to validate. No spaces or tab are allowed at the start or at the end of the string
 * @returns true of false if the email is valid or not
 */
function isEmail(email: string) : boolean {
  // An email address is a word followed by an unique @ followed by a word then a . followed by a word with a length of 2 to 3 characters
  const regEx = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/
  const result = regEx.test(email)
  return result
}


export {
  isEmail
}
Enter fullscreen mode Exit fullscreen mode

Create a file ipV4.js in ./src/validators/ directory


/**
 * @param ip to validate. (No spaces or tab are allowed at the start or at the end of the string)
 * @returns true of false if the IP is valid or not
 */
function isIPv4(ip: string) : boolean {
  // An ip V4 address has the form of X.X.X.X
  // Where X is a number between 0 to 255
  const regEx = /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
  const result = regEx.test(ip)
  return result
}


export {
  isIPv4
}
Enter fullscreen mode Exit fullscreen mode

Create a file index.ts in ./src/

import { isEmail } from "./validators/email"
import { isIPv4 } from "./validators/ipv4"

export { isEmail, isIPv4 }
Enter fullscreen mode Exit fullscreen mode

Our module is now nearly ready. Let's create the unit tests.

Creation of unit tests

Create an email.test.ts in ./src/tests directory

import { isEmail } from "../src/index"

test("email luc@perdu.com valid", () => {
  expect(isEmail("luc@perdu.com")).toBe(true)
})

test("Empty string not valid", () => {
  expect(isEmail("")).toBe(false)
})

test("No double @ in an email", () => {
  expect(isEmail("martin@toto@titi.com")).toBe(false)
})

test("not trimmed email to be false", () => {
  expect(isEmail(" luc@perdu.com ")).toBe(false)
})

Enter fullscreen mode Exit fullscreen mode

Create the ipV4.test.ts in ./src/tests/ directory

import { isIPv4 } from "../src"

test("192.168.0.1 is valid", () => {

    expect(isIPv4("192.168.0.1")).toBe(true)
})

test("1920.168.0.1 is not valid", () => {

  expect(isIPv4("1920.168.0.1")).toBe(false)
})

test("192.1682.0.1 is not valid", () => {

  expect(isIPv4("192.1682.0.1")).toBe(false)
})

test("192.168.256.1 is not valid", () => {

  expect(isIPv4("192.168.256.1")).toBe(false)
})

test("192.168.255.500 is not valid", () => {

  expect(isIPv4("192.168.255.500")).toBe(false)
})

test("192.168.255.255 is valid", () => {
  expect(isIPv4("192.168.255.255")).toBe(true)
})

test("192.168.X.255 is valid", () => {
  expect(isIPv4("192.168.X.255")).toBe(false)
})

Enter fullscreen mode Exit fullscreen mode

Let's compile and tests

yarn build
Enter fullscreen mode Exit fullscreen mode
yarn test
Enter fullscreen mode Exit fullscreen mode

Execute the tests coverage

yarn coverage
Enter fullscreen mode Exit fullscreen mode

A coverage has been generated with all the information about the tests coverage

Creation of git repository

Create of a .gitignore file

node_modules
build
coverage
Enter fullscreen mode Exit fullscreen mode

run git init

git init
Enter fullscreen mode Exit fullscreen mode

add the files

git *
Enter fullscreen mode Exit fullscreen mode

commit the files

git commit -m "First commit"
Enter fullscreen mode Exit fullscreen mode

Publish the file to a Github repository

An empty Github project must be created before publishing.

The file package.json need to be updated as follow:

  "repository": {
    "url": "https://github.com/myorganisation/xanthe.git",
    "type": ""
  },
Enter fullscreen mode Exit fullscreen mode

myorganisation represents your Github account

We can now set up the Github project as a remote representation of the local project and push the local master branch to the remote server (origin).

git remote add origin`https://github.com/myorganisation/xanthe.git
git branch -M master
git push -u origin master
Enter fullscreen mode Exit fullscreen mode

Publish to npmjs.org

An account must be created before publishing a package in the npm registry.

  • Once the account is created you need to log into
npm login
Enter fullscreen mode Exit fullscreen mode
  • Enter your username, password, and email address registered on npmjs.org

  • Add a new file .npmignore to exclude some files from the publication

README.md
TUTORIAL.md
jest.config.json
tests/
Enter fullscreen mode Exit fullscreen mode
  • We can now publish it to the library at npmjs.org
yarn publish
Enter fullscreen mode Exit fullscreen mode

A few questions will be asked such as the new version number 0.0.1

And "voilà". Our components are published and visible 🥳

💖 💪 🙅 🚩
raphaelmansuy
Raphael MANSUY

Posted on September 6, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related