DEV Community

Cover image for Setup a simple Node Typescript Project in 5 minutes - 2024 edition
Aro
Aro

Posted on

Setup a simple Node Typescript Project in 5 minutes - 2024 edition

This article was originally posted on my blog

We are in May 2024, I just want to setup a simple Node project. But it’s so freaking hard. I tried every blog post in google’s first page results. None are working, at least as I want it.

Why is it so ducking 🦆 hard to have a Node development setup that is in Typescript and uses ESM !?

So, after a frustrating couple of hours of searching and tweaking, I finally found a way to have a simple setup that just works (for now)

Requirements

So as I said, I want to it to use

  • Typescript
  • ESM - import and export
  • Node 20 (this is a LTS version)

That’s literally it.

The solution

Dependencies

First of all, install all the dependencies

pnpm i -D typescript @types/node tsx tsc-alias rimraf
Enter fullscreen mode Exit fullscreen mode
  • typescript and @types/node : those are the usual packages needed for every TS project. Nothing special here
  • tsx : for typescript code execution. It is a replacement of ts-node. As the latter does not work in Node 20
  • tsc-alias : for replacing alias paths after typescript compilation
  • rimraf : a simple utility for deleting the dist folder before each compilation

DISCLAIMER: I am NOT an experienced Node developer. I mostly work in frontend development with React. This is just a simple node setup that works for me. I am sure it’s possible to make it even simpler without relying on third party dependencies like tsx and tsc-alias.. But I am just not in the mood of digging further 🥲

tsconfig.json

For the tsconfig file, I use the config from this TotalTypescript blog post.

NOTE : I did try to follow this blog post steps. But I didn’t like to have two dev scripts that run concurrently. At the time, I was playing with some AI stuff and was trying to console.log the stream response from the AI, and it just didn’t get displayed to the console. I suspect this concurrent run of two dev scripts.

{
  "compilerOptions": {
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "es2022",
    "allowJs": true,
    "resolveJsonModule": true,
    "moduleDetection": "force",
    "isolatedModules": true,
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "moduleResolution": "NodeNext",
    "module": "NodeNext",
    "outDir": "dist",
    "sourceMap": true,
    "lib": ["es2022"],

    /* I add this part because I want absolute imports */
    "baseUrl": ".",
    "paths": {
      "src/*": ["src/*"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

package.json

{
  "type": "module",
  "scripts": {
    "build": "rimraf dist && tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
    "dev": "NODE_ENV=development tsx --watch --env-file=.env src/index.ts",
    "start": "node --env-file=.env dist/index.js"
  },
  "engines": {
    "node": "20"
  }
}
Enter fullscreen mode Exit fullscreen mode
  • type:"module" : tells Node to use ESM
  • build : builds the project with tsc and replaces alias paths with tsc-alias
  • dev : here lies the magic, tsx just works and can be used as a replacement of node. All node arguments can be used with tsx and that is awesome
  • start : runs the compiled files with Node
  • --env-file : loads environment variables, so no need of dotenv anymore
  • --watch : watch mode introduced in Node 18

Caveats when importing a file

This is the last thing you want to be aware of. When importing a file, you have to suffix the import paths with .js

import { hello } from "src/utils/hello.js";
Enter fullscreen mode Exit fullscreen mode

Conclusion

And that’s it, holy cow I struggled so much just to find this setup. Some of you that are already familiar with tsx may call me a noob 😅 and you are not totally wrong.

I was used to use nodemon and ts-node before but my previous setup don’t work anymore 🤷🏽‍♂️

I think it is not not normal that it’s so hard to setup a modern Node project but also to find the right information to do that, as there are literally no single way of doing this.

But in the end I am happy that I succeed (for now). Thanks for reading, ciao ciao

You can find the complete repo here

This article was originally posted on my blog

Your turn

So what do you think about this setup ? Is there a way to simplify it more ?

Top comments (0)