Journey of creating and publishing a nodejs package with typescript & eslint support
Tags: typescript, beginners, devops, node
Published: 2023-09-08 22:26:38

Today we will discuss how I've written a npm package and published it to [npmjs](https://www.npmjs.com/package/phil-s-osophy). 

> You can checkout the codebase from [here](https://github.com/MitraKumar/phil-s-osophy)

This is a simple package which just generates random quotes from Phil Dunphy, the lovable and hilarious character from the TV show Modern Family.  I have chosen Phil Dunphy as I love Mordern Family and he is one of my favorite caracter from the show.

The target of this package was not to create something unique and useful for everyone (though if you are a fan of Phill Dunphy you may love this idea 😉), but it was to learn how we can use these technologies to build packages in a simple and efficient manner.

#### Technology Used

- Typescript for writing the business logic and have used [tsup](https://tsup.egoist.dev/) for compiling to javascript files. 
- ESlint for linting the typescript code
- Also have used Github Actions for linting the code whenever a new pull request is being created.

#### Setting up local environment for creating packages

For setting up a local environment, we can start like a basic node js project.

```bash
mkdir my_project
cd my_prject
npm init
```

After that we need to add the main entry point of our package as well as a bin file.

```json
{
  "name": "phil-s-osophy",
  "version": "1.0.1",
  "description": "Phil Dunphy's amazing life lessons from Mordern Family.",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  ...
  "bin": {
    "phil-o-osophy": "./dist/index.js"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/MitraKumar/phil-s-osophy.git"
  },
  "author": "MitraKumar",
  "license": "MIT",
  "bugs": {
    "url": "https://github.com/MitraKumar/phil-s-osophy/issues"
  },
  "homepage": "https://github.com/MitraKumar/phil-s-osophy#readme",
  ...
}
```

In my scenario since it I am compiling the javascript with tsup I've added the files in here.

And in the typescript file we need to add shebang in front of the file
```ts
#! /usr/bin/env node

```

After updating all this we can simply run `npm install -g .` from the project directory to use the package.

#### Project Setup with Typescript

The main business logic for the package is written in typescript and the logic is very simple, it's just accessing a random element from a list of quotes and printing it out. Again the project was not to create anything unique, it is just fun enough for me to learn these things.

For compiling typescript file I have used tsup as a dev dependency, which is very useful and intuitive for compiling to javascript files. To make this process seamless I've added a npm script to build the project.

For the configuration of tsup we need to create a `tsup.config.ts` file.
```ts
import { defineConfig } from 'tsup'

export default defineConfig({
  target: 'es2020',
  format: ['cjs', 'esm'],
  splitting: false,
  sourcemap: true,
  clean: true,
  dts: true
})
```

Then after adding this I added the build command in npm scripts and voila it all worked seamlessly.

```json
{
  "name": "phil-s-osophy",
  ...
  "scripts": {
	...
    "build": "tsup ./src"
  },
  ...
}
```

This is really helpful as we get the power of types and the seamless process of compiling to javascript files.

#### Linting with ESLint

Linting is must in a project, this is a small simple enough project but for a live project with many contributors linting is must otherwise without following a proper coding standard it will be difficult over time to maintain a project.

I have used ESlint for checking the linting of the project. Setting up ESLint is simple enough but we have to add few dependencies to help us out here...

in the package.json we need to add few of the dev dependencies such as
```json
{
  ...
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^6.6.0",
    "@typescript-eslint/parser": "^6.6.0",
    "eslint": "^8.48.0",
    ...
  }
}
```

We can install this dependencies by running
```bash
npm install -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
```

After that we need to add a `.eslintrc` file, with some basic rulesets.
```json
{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "@typescript-eslint/no-explicit-any": "error",
    "indent": ["error", 2],
    "linebreak-style": ["error", "unix"],
    "quotes": ["error", "double"],
    "semi": ["error", "always"]
  }
}
```

And all the configurations are done, now we can simply add a npm script `eslint ./src --ext .ts` to lint our files.

But this will cause an issue as ESLint will not trigger any typescript error, for that we can simply check it with `tsc --noEmit ./src/index.ts`. So for linting we can simply add a script like this `tsc --noEmit ./src/index.ts; eslint ./src --ext .ts` to run both of them sequentially.

Also we can add a script to fix the linting errors with ESlint.
```
{
  ...
  "scripts": {
    "lint": "tsc --noEmit ./src/index.ts; eslint ./src --ext .ts",
    "fix": "eslint ./src --ext .ts --fix",
    ...
  },
  ...
}
```

And voila, linting is also setup in our project.


#### Setting up Github Actions for checking coding standards

In a real world we probably cannot expect everyone to properly lint code and the Pushing it. So we need to setup a Github Action to generate a check for linting errors if any whenever a PR is being generated.

Setting up such action is pretty easy, we just need create a yml file in the directory `.github/workflows` like I've created a file `.github/workflows/linter.yml`
```yml
name: Code Checker

on:
  pull_request:
    branches:
      - main

jobs:
  linting:
    runs-on: ubuntu-latest
    name: Checking coding standards & type checking.
    steps:
      - name: Checkout
        uses: actions/checkout@v3
      - name: Setup node environment
        uses: actions/setup-node@v3
        with:
          node-version: 'latest'
      - name: Install dependencies
        run: npm clean-install
      - name: Run linting & type checking
        run: npm run lint
```

This workflow file is mainly divided into three sections

- name - Name of the workflow
- Event - On which event the workflow will trigger, like in this scenario it will trigger on creating a Pull request against the branch `main`
- Jobs - What jobs will run in this workflow.

Jobs also have several aspects to understand, the main thing being `steps`
Steps basically mentions what the a job will do in a sequential order, like here it is mentioned that the job will first checkout the repo, then setup node environment then install all dependencies and then run our lint script from above.

And that's it, now creating a PR will automatically run this jobs and will show a green check mark ✅
![Github Screenshot for Workflow Action Checks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vm6hp0k9syylsgq4t548.png)

### Conclusion

So in conclusion I will say, this was a fun simple enough project which helped me learn a lot of things. And if any of you have any idea of improving the project, even if it's a change in README file, you are more than welcome to submit a Pull Request and I will be happy to merge it.