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

Development
Sunday, September 6, 2020

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

1{
2 "name": "xanthe",
3 "version": "0.0.1",
4 "author": {
5 "email": "contact@elitizon.com",
6 "name": "elitizon"
7 },
8 "license": "MIT",
9 "description": "A library to validate common formats such as emails, numbers, phone numbers, and IP addresses",
10 "contributors": [
11 "raphaelmansuy"
12 ],
13 "keywords": [
14 "format",
15 "validator",
16 "email validation",
17 "IP address validation"
18 ],
19 "dependencies": {},
20 "devDependencies": {}
21}

Install typescript as a development dependencies

1yarn add -D typescript @types/node

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

Create the src and test directory

1mkdir src
1mkdir tests

Install a testing environment

Install Jest as a development dependency

Jest is a testing library developed by Facebook.

1yarn add -D jest ts-jest

Create a jest.config.js file to configure Jest

1module.exports = {
2 transform: {'^.+\\.ts?$': 'ts-jest'},
3 testEnvironment: 'node',
4 testRegex: '/tests/.*\\.(test|spec)?\\.(ts|tsx)$',
5 moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node']
6}
  • All the files ending by .ts will be handled by ts-jest.
  • The test environment is nodejs
  • The test files are situed in the ./tests 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

1"scripts": {
2 "build": "tsc",
3 "test": "yarn build && jest",
4 "coverage": "jest --coverage"
5 },
  • 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

1{
2 "compilerOptions": {
3 "target": "es5" ,
4 "module": "commonjs",
5 "outDir": "./build",
6 "strict": true,
7 "esModuleInterop": true ,
8 "skipLibCheck": true,
9 "forceConsistentCasingInFileNames": true,
10 "declaration": true
11 },
12 "exclude": ["node_modules", "build", "tests"]
13}

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

Creation of the validations functions

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

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

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

1/**
2 * @param ip to validate. (No spaces or tab or is allowed at the start or at the end of the string)
3 * @returns true of false if the IP is valid or not
4 */
5function isIPv4(ip: string) : boolean {
6 // An ip V4 address has the form of X.X.X.X
7 // Where X is a number between 0 to 255
8 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]?)$/
9 const result = regEx.test(ip)
10 return result
11}
12
13
14export {
15 isIPv4
16}

Create a file index.ts in ./src/

1import { isEmail } from "./validators/email"
2import { isIPv4 } from "./validators/ipv4"
3
4export { isEmail, isIPv4 }

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

Creation of the unit tests

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

1import { isEmail } from "../src/index"
2
3test("email luc@perdu.com valid", () => {
4 expect(isEmail("luc@perdu.com")).toBe(true)
5})
6
7test("Empty string not valid", () => {
8 expect(isEmail("")).toBe(false)
9})
10
11test("No double @ in an email", () => {
12 expect(isEmail("martin@toto@titi.com")).toBe(false)
13})
14
15test("not trimed email to be false", () => {
16 expect(isEmail(" luc@perdu.com ")).toBe(false)
17})

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

1import { isIPv4 } from "../src"
2
3test("192.168.0.1 is valid", () => {
4
5 expect(isIPv4("192.168.0.1")).toBe(true)
6})
7
8test("1920.168.0.1 is not valid", () => {
9
10 expect(isIPv4("1920.168.0.1")).toBe(false)
11})
12
13test("192.1682.0.1 is not valid", () => {
14
15 expect(isIPv4("192.1682.0.1")).toBe(false)
16})
17
18test("192.168.256.1 is not valid", () => {
19
20 expect(isIPv4("192.168.256.1")).toBe(false)
21})
22
23test("192.168.255.500 is not valid", () => {
24
25 expect(isIPv4("192.168.255.500")).toBe(false)
26})
27
28test("192.168.255.255 is valid", () => {
29 expect(isIPv4("192.168.255.255")).toBe(true)
30})
31
32test("192.168.X.255 is valid", () => {
33 expect(isIPv4("192.168.X.255")).toBe(false)
34})

Let's compile and tests

1yarn build
1yarn test

Execute the tests coverage

1yarn coverage

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

Creation of git repository

Create of a .gitignore file

1node_modules
2build
3coverage

run git init

1git init

add the files

1git *

commit the files

1git commit -m "First commit"

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:

1"repository": {
2 "url": "https://github.com/myorganisation/xanthe.git",
3 "type": ""
4 },

myorganisation represents your Github account

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

1git remote add origin`https://github.com/myorganisation/xanthe.git
2git branch -M master
3git push -u origin master

Publish to npmjs.org

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

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

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

1README.md
2TUTORIAL.md
3jest.config.json
4tests/
  • We can now publish to the library to npmjs.org
1yarn publish

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

And voila our component is published and visible 🥳

Subscribe to our Newsletter

We deliver high quality blog posts written by professionals monthly. And we promise no spam.

elitizon ltd.

© 2020 elitizon ltd. All Rights Reserved.