Create a JavaScript library using Typescript, Jest and Rollup

Recently I was working on a personal JS library Serina. It is a open source library, I wanted to use Typescript (TS) to ensure better stability due to it is static typed. It should make the code base more readable and therefore easier to contribution.

There are many ways to build projects, and Rollup is just one of them. I decided to go with Rollup because it is much lighter than something like Webpack, but it is still very well supported in terms of plugins. Most importantly, I've used it in other projects and I'm lazy :P All jokes aside, I have to say Rollup is my go to build tool right now.

In this blog, I have broken down each part of the project into different sections, so it is easily to find alternative options if prefered. E.g. rather than using Typescript, you can simple skip it.

Setup core library

Like all JavaScript projects, first create project folder and within the project folder run npm init to initialise it.

Create a src folder and then create an empty file inside it. It should now look something like this:

yourFolder
    |-- package.json
    |-- src
        |-- myLib.ts

Inside the myLib.ts file is where the library logic will live, but let's do something simple for now. In the follow example, our library will simple take in a string then return it back. It is pretty useless, but for the purpose of this blog I'm going to keep it like this so it is easier to follow.

export default myLib = (text: string): string {
    return text;
}

Typescript

Install Typescript npm package by running npm i typescript (or use npm install).

It is always a good idea to configure the compiler options of Typescript to fit your coding pattern, and pick up on any potential issues with the code when it compiles. Create a file called tsconfig.json at root folder level with the following config:

{
  "version": "2.5.0",
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "diagnostics": true,
    "target": "ES5",
    "downlevelIteration": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitReturns": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "removeComments": true,
    "noLib": false,
    "moduleResolution": "node",
    "sourceMap": true,
    "typeRoots": [
      "/.node_modules/@types"
    ]
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "src/**/*.test.ts"
  ]
}

The folder should now look like this:

yourFolder
    |-- package.json
    |-- tsconfig.json
    |-- src
        |-- myLib.ts

Code linting

It is always important to have linting setup for any project to ensure code standards and catch silly errors when coding. Since I'm using Typescript, therefore TSlint is my choice here, but feel free to use ESlint if you wish to use pure JavaScript.

Let's install tslint and the extra eslint rules by running npm i tslint tslint-eslint-rules.

Now create tslint.json file in the root project directory.

yourFolder
    |-- package.json
    |-- tsconfig.json
    |-- tslint.json
    |-- src
        |-- myLib.ts

Inside the file, paste in something like the following. This is my prefered setup, but feel free to tweak it however you see fit.

{
  "extends": [
    "tslint:recommended",
    "tslint-eslint-rules"
  ],
    "defaultSeverity": "warning",
    "jsRules": {},
    "rules": {
      "curly": [true, "ignore-same-line"],
      "interface-name": [true, "never-prefix"],
      "max-line-length": [true, 180],
      "object-literal-sort-keys": false,
      "trailing-comma": [true, {"multiline": "never", "singleline": "never"}],
      "arrow-parens": false,
      "member-access": [true, "no-public"],
      "eofline": false,
      "whitespace": [false, "check-module"],
      "no-angle-bracket-type-assertion": false,
      "ordered-imports": false,
      "quotemark": [true, "single", "avoid-escape"],
      "object-curly-spacing":[true, "always"]
    },
    "rulesDirectory": []
}

For more information on the above rules, refer to the official documentation.

Inside package.json I would recommend adding 2 npm scripts related to linting. npm run lint will check for all the TS files within src folder for mistakes, and npm run lint:fix will fix all the mistakes it can automatically (e.g. it is nice not having to go in different files and remove a whole bunch of white spaces).

"lint": "tslint -c tslint.json \"src/**/*.ts\"",
"lint:fix": "tslint --fix -c tslint.json \"src/**/*.ts\""

Setup Test

In order to get test set up, we will need to install Jest and the related packages by running npm i jest ts-jest @types/jest.

Then add the following Jest config inside package.json. This will be used to pick up test files and etc.

{
  ...

  "jest": {
    "transformIgnorePatterns": [
      "node_modules/(?!shiva/)"
    ],
    "globals": {
      "ts-jest": {
        "tsConfigFile": "tsconfig.test.json"
      },
      "google": {}
    },
    "collectCoverageFrom": [
      "src/**/*.ts",
      "!src/**/*.schema.ts",
      "!src/schema/*.ts"
    ],
    "testMatch": [
      "<rootDir>/src/**/?(*.)test.ts",
      "<rootDir>/tests/**/?(*.)test.ts"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 0,
        "functions": 0,
        "lines": 0,
        "statements": 0
      }
    },
    "moduleFileExtensions": [
      "ts",
      "js"
    ],
    "transform": {
      "\\.(ts)$": "<rootDir>/node_modules/ts-jest/preprocessor.js",
      "^.+\\.js$": "babel-jest"
    }
  }

  ...
}

Setup Build

To set up Rollup, first install Rollup and TS plugin by running npm i rollup rollup-plugin-typescript2.

Now create a rollup.config.js file in the root project directory. Inside this file create a simple rollup config like the following:

import typescript from 'rollup-plugin-typescript2';

export default {
  input: 'src/myLib.ts',
  output: [{
    name: 'MyLib',
    file: 'dist/myLib.js',
    format: 'umd'
  }],
  plugins: [
    typescript()
  ]
}

The project structure should now look like this:

yourFolder
    |-- package.json
    |-- rollup.config.js
    |-- tsconfig.json
    |-- tslint.json
    |-- src
        |-- myLib.ts

Now, again inside package.json and add in some npm scripts for building the project. npm run build will call other npm scripts and then at the end compile the TS into JS and place it in the dist folder.

"build": "npm run lint && npm run test && npm run clean && rollup --config",
"clean": "rm -rf ./dist && mkdir dist"

Icing on the cake

Since it is going to be an open source library, it is also worth considering doing the following to give people more confidence in the project:

  • Add a README.md file
  • Add a LICENSE file so people know how they can use your code
  • Set up CI/CD, and then place a badge in the README to show the code bade status (e.g. passing, failing)
  • Consider adding an .editorconfig file

That's it!

Hope this was relatively straight forward to follow, I tried to cover all the aspects in this blog and answer the common questions. Please let me know in the comments if there's anything I missed or hit me up on Twitter!

Buy Me A Coffee