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 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. The code is a fork from thedrlambda 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.
"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.
> 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.
> 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.
"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.
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.
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
.
"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.
<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.
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 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:
> 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
:
"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:
> 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.
npm i eslint-plugin-spellcheck --save-dev
To enable the spellchecker in ESLint, edit the .eslintrc.cjs
file:
"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
.
"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), now is your chance. Mocha 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:
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:
{
"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.
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, the transition will feel seamless.
Lastly, be sure to include Mocha in package.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. 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 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.
Top comments (0)