5 Node.js Tools to Learn in 2023
Tags: node
Published: 2023-02-08 15:09:37

The Node ecosystem comes with a wide variety of tools that have continued to evolve over the years. These tools are delivered via NPM packages and run in the command line, making them accessible to any developer (you do not need a fancy IDE to get the job done).

In this take, we will explore 5 Node tools to learn this year: TypeScript, ES modules, ESLint, the ESLint SpellCheck plugin, and Mocha. These all run via the command line and can help boost your productivity when working on Node projects.

Ready? Let’s go!

## The Sample Code

If you want to get a head start, the sample code is a code kata with all the tools discussed in this article. It is an HTML5 game by [Christian Clausen](https://github.com/thedrlambda) called bomb-guy that you can run in the browser. The emphasis will not be on the code itself but on the tools around the code solution.

Feel free to clone the repo — it is available on [GitHub](https://github.com/beautifulcoder/bomb-guy). The code is a fork from [thedrlambda](https://github.com/thedrlambda/bomb-guy) and has been refactored with all these tools.

Be sure to inspect the `package.json` file to get a sneak peek of all the cool tools available.

```json
"devDependencies": {
  "@types/mocha": "^10.0.1",
  "@typescript-eslint/eslint-plugin": "^5.47.0",
  "eslint": "^8.30.0",
  "eslint-config-standard-with-typescript": "^24.0.0",
  "eslint-plugin-import": "^2.26.0",
  "eslint-plugin-n": "^15.6.0",
  "eslint-plugin-promise": "^6.1.1",
  "eslint-plugin-spellcheck": "^0.0.20",
  "http-server": "^14.1.1",
  "jsdom": "^20.0.3",
  "jsdom-global": "^3.0.2",
  "mocha": "^10.2.0",
  "ts-node": "^10.9.1",
  "typescript": "^4.9.4"
}
```

Remember, these all run via the command line, so you do not need a fancy editor or IDE to use them. Simply do `npm run build`, `npm test`, or `npm start` to spin up all the dev tools. This is the typical dev flow for pretty much all Node projects.

We will discuss each tool as a reference guide, show you how to get started, and point out a few gotchas. The emphasis is on playing around with each tool and showing you how to use it.

Let’s start with TypeScript.

## TypeScript for Your Node.js Project

I’m sure you’ve already heard this a lot, but if you haven’t tried TypeScript in a project, you really need to. TypeScript adds type safety to your projects and makes it easier to catch mistakes in the code. For this bomb-guy code kata, for example, it’s valuable to rely on the compiler when making a lot of changes.

To get started, be sure to create a `package.json` file if you don’t already have one via `npm init`. Then, add the TypeScript dependency.

```shell
> npm i typescript --save-dev
```

At this point, it is possible to add the `tsc` command as a `build` script in `package.json`. If you have a bunch of existing JavaScript files, any file that gets renamed with a `.ts` extension becomes a TypeScript file, and the compiler does the rest of the work.

Most dev workflows require some tweaking of the compiler configuration. The way you do this is via the initializer.

```shell
> npx tsc --init
```

This creates a `tsconfig.json` file with the default configuration. Each configuration is well documented within this file so that you can tailor the tool to your needs.

While you are in the configuration file, change the TypeScript configuration so we can talk about the next available tool.

```json
"compilerOptions": {
  "module": "esnext",
  "target": "esnext"
}
```

Now it is possible to declare strongly typed interfaces and classes.

As an example, let’s say we want to declare an interface every tile class must implement in this bomb-man game. The game is a 2-D style game with many different types of tiles.

```typescript
interface Tile {
  isGameOver: () => boolean;
  draw: (g: CanvasRenderingContext2D, x: number, y: number) => void;
  move: (x: number, y: number) => void;
  update: (x: number, y: number) => void;
  placeBomb: () => void;
  explode: (x: number, y: number, fire: Tile) => void;
}
```

Voilà! If you want more information about setting up TypeScript for your Node app, check out the post [How to Set Up a Node.js Project with TypeScript](https://blog.appsignal.com/2022/01/19/how-to-set-up-a-nodejs-project-with-typescript.html).

Next up, let’s see what ES modules have to offer.

## ES Modules in Node.js and the Browser

Both Node and the browser have achieved parity via export/import. This module system allows you to simply `import` code from different files and works natively without transpilers.

In Node, change the `package.json` file to a `module`.

```json
"type": "module"
```

This instructs Node to start using ES modules natively, without the TypeScript transpiler.

In the browser, go to `index.html` and change the `script` tag.

```html
<script src="dist/src/index.js" type="module"></script>
```

This achieves two things:

- TypeScript does not nuke the export/import code
- The browser can use this same module system to tackle dependencies

One gotcha here is that there is a bit of divergence between TypeScript and the browser. The spec says imported modules must declare a file extension, whereas TypeScript makes the resolution even without an extension like `.js`.

To tackle this issue, simply declare all dependencies as JavaScript files in your TypeScript code. The compiler is smart enough to know that you mean to declare the import as a JavaScript file.

```typescript
import { TILE_SIZE, FPS, TPS } from "./constant.js"; // JavaScript file imported
```

This technique works seamlessly in both Node and the browser.

## ESLint with TypeScript for Your Node.js App

The linter tool [ESLint](https://eslint.org/) statically analyzes code, supports most text editors, and can run in the command line. It adds code smell checks, checks for potential bugs, and even helps style code consistently. We recommend turning on all the features ESLint has to offer.

To get started, initialize the config package:

```shell
> npm init @eslint/config
```

This CLI tool automatically guides you through a set of options where you can customize the configuration. Be sure to pick all three: check syntax, find problems, and enforce code style. Pick the standard, most popular style guide — ESM — as the module system and TypeScript.

The configuration file comes in three flavors: JavaScript, JSON, and YAML. Pick JavaScript because we need to tackle the next gotcha.

For ESLint to work with the TypeScript compiler, it needs `parserOptions` somewhere in the configuration file. Also, because we are using the ES module system in `package.json`, we must rename the configuration file to `.eslintrc.cjs`.

In `.eslintrc.cjs` be sure to set the `parserOptions`:

```javascript
"parserOptions": {
  "project": ["tsconfig.json"],
  "tsconfigRootDir": __dirname, // JavaScript code
  "ecmaVersion": "latest"
}
```

Note the use of `__dirname` — this allows the linter to find the `tsconfig.json` file from anywhere in the project folder structure. This technique is only achievable via the JavaScript configuration file.

Now lint a file in the `src` folder:

```shell
> npx eslint constant.ts
```

There you have it! Next up is a handy ESLint plugin: SpellCheck.

## ESLint Plugin — SpellCheck

ESLint is extensible via plugins. Because there is nothing less annoying than typos in code, let’s install the [`spellcheck` plugin](https://www.npmjs.com/package/eslint-plugin-spellcheck).

```shell
npm i eslint-plugin-spellcheck --save-dev
```

To enable the spellchecker in ESLint, edit the `.eslintrc.cjs` file:

```json
"plugins": ["spellcheck"],
"rules": {
  "spellcheck/spell-checker": [
    "warn", {
      "skipWords": ["rect", "keydown"]
    }
  ]
}
```

This fires warnings in ESLint when it finds a spelling mistake. If you have valid words that are not found in the dictionary, just add them to the list in `skipWords`.

With ESLint, most caught issues trigger an error, and the build will fail until the issue is fixed. This makes the CLI tool ideal for both local development and continuous integration on a build server.

To enable these checks automatically, add ESLint to the `prebuild` script in `package.json`.

```json
"scripts": {
  "prebuild": "eslint ."
}
```

Finally, let’s take a look at Mocha.

## Mocha for Testing in Node.js

If you have yet to practice [test-driven development (TDD)](https://www.agilealliance.org/glossary/tdd/), now is your chance. [Mocha](https://mochajs.org/) integrates seamlessly with all the tools we have covered so far and can run hundreds of unit tests in less than a second.

To get started with Mocha, install the following dependencies:

```shell
npm i @types/mocha jsdom jsdom-global ts-node mocha --save-dev
```

Note the use of `ts-node` and `jsdom` in the dependencies. The bomb-guy code kata runs in the browser, so `jsdom` allows mocking browser elements like the `window` object without a headless browser.

Because we are using TypeScript, `ts-node` is an execution engine that directly executes TypeScript on Node without precompiling. These two dependencies are useful for running unit tests in Mocha.

To enable these tools in Mocha, create a `.mocharc.json` file with the following configuration:

```json
{
  "require": ["jsdom-global/register"],
  "loader": "ts-node/esm",
  "extensions": ["ts"],
  "spec": ["tests/**/*.test.ts"]
}
```

This tells Mocha to enable three things: `jsdom`, `ts-node` with ES modules, and the TypeScript extensions. The `spec` settings specify where the tests go, and you can use a glob pattern.

Then, write the unit tests using TypeScript. Say we want to test that a player can move around the tiles and place a bomb.

```typescript
it("move player", () => {
  player.moveRight();
  player.moveDown();
  player.moveDown();
  equal(2, player.x); // assertion library
});

it("place first bomb", () => {
  player.placeBomb();
  map.update();
  equal(1, player.bombs);
});
```

_Note that Mocha does not come with an assertion library._

Thankfully, Node comes with one built-in, so you do not have to add another dependency. If you are already familiar with [Chai](https://www.chaijs.com/), the transition will feel seamless.

Lastly, be sure to include Mocha in `package.json`:

```json
"scripts": {
  "test": "mocha"
}
```

The `.mocharc.json` configuration file already tells Mocha how to run the tests. This technique keeps your `package.json` file clutter-free.

One gotcha is that Mocha does not support [ESM in watch mode](https://github.com/mochajs/mocha/issues/4374). Hopefully, this limitation will be tackled in future releases.

Keep in mind, the linter and compiler are separate from running unit tests in your continuous integration pipeline. The execution engine in `ts-node` is not a compiler and does not do any code checks. So a good technique is to run both ESLint and the TypeScript compiler first, then run unit tests last on the build server.

## Wrapping Up

In this post, we explored 5 Node tools to learn this year: TypeScript, ES modules, ESLint, the ESLint SpellCheck plugin, and finally, Mocha for running tests.

These Node tools offer the possibility of tackling code changes without an IDE. The tools are accessible and do not shove specific IDEs or text editors on developers. They are easy to automate and can be included in continuous integration so an entire team can benefit.

Happy coding!

**P.S. If you liked this post, [subscribe to our JavaScript Sorcery list](https://blog.appsignal.com/javascript-sorcery) for a monthly deep dive into more magical JavaScript tips and tricks.**

**P.P.S. If you need an APM for your Node.js app, go and [check out the AppSignal APM for Node.js](https://www.appsignal.com/nodejs).**