ReactHustle

How to Configure Typescript baseUrl in a Node.js Project

Jasser Mark Arioste

Jasser Mark Arioste

How to Configure Typescript baseUrl in a  Node.js Project

Hello, hustlers! In this tutorial, you will learn how to configure baseUrl option in Typescript to enable absolute imports for your code. 

The Problem #

If you want clean code, one of the practices is to use absolute imports in a NodeJS typescript project. by using the baseUrl option in your tsconfig.json file. You could turn this:

import MyService from "../../services/MyService"
1

Into this:

import MyService from "services/MyService"
1

In VS Code it would work absolutely perfectly.

However, when I built my code using tsc command and ran it using node ./dist/index.js, I got this error:

$ node ./dist/index.js
node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module 'services/MyService'
Require stack:
- D:\Blog\typescript-absolute-imports\dist\index.js
1234567

This happens because javascript does not recognize absolute imports. If we check the outputted js files, the tsc command doesn't transform the path to relative imports:

// dist/index.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var MyService_1 = __importDefault(require("services/MyService"));
console.log(new MyService_1["default"]());
12345678

Configuring baseUrl for Production #

To configure baseUrl for production and fix the "Cannot find module" error,  you need to use the tsc-alias package. There might be other ways to solve this, but I find this approach straightforward and simple.

Suppose you have the following project structure:

|- /dist
|- /node_modules
|- /src
   |- index.ts    
|- package.json
|- tsconfig.json
12345

Step 0: Configuring tsconfig.json

All source code is located inside the/src folder and will be outputted to the /dist folder after the build.  First, configure your tsconfig.json to use baseUrl:

// tsconfig.json
{
  "compilerOptions": {
    "module": "CommonJS",
    "outDir": "./dist",
     //...other options
    "baseUrl": "./src"
  }
}
123456789

Step 1: Installing tsc-alias package

Next, let's install the tsc-alias package:

yarn add -D tsc-alias
# or
npm i -save-dev tsc-alias

Step 2: Modifying package.json

Next, let's modify package.json to include tsc-alias in the "build" script. This will transform the absolute paths into relative paths after the tsc command which completely solves our problem.

{
  ...
  "scripts": {
    "build": "tsc && tsc-alias",
    "start": "node ./dist/index.js",
  },
  "devDependencies": {
    "tsc-alias": "^1.7.1",
    "typescript": "^4.9.3"
  }
}

Step 3: Testing

Finally, let's test our script using yarn build and yarn start

$ yarn build
yarn run v1.22.17
$ tsc && tsc-alias
Done in 1.61s.

$ yarn start
yarn run v1.22.17
$ node ./dist/index.js
Hello, MyService
MyService {}
Done in 0.09s.

Yahoo! There are no errors! Next, let's check the outputted files inside dist/index.js:

// dist/index.js
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
exports.__esModule = true;
var MyService_1 = __importDefault(require("./services/MyService"));
console.log(new MyService_1["default"]());
12345678

It's now using relative import, not bad.

With this, we have configured the baseUrl option for production. What about development?

Configuring baseUrl for Development #

For development, I like to use the ts-node-dev and tsconfig-paths packages to solve the absolute import problem.  First, let's install both packages:

yarn add -D ts-node-dev tsconfig-paths
# or
npm i --save-dev ts-node-dev tsconfig-paths

Then, add a "dev" script to our package.json file:

{
  "scripts": {
    "dev": "ts-node-dev -r tsconfig-paths/register ./src/index.ts"
  }
}

Make sure you adjust if you have a different path for your index.ts file.

Finally, you can run yarn dev command: 

$ yarn dev
yarn run v1.22.17
$ ts-node-dev -r tsconfig-paths/register ./src/index.ts
[INFO] 16:47:13 ts-node-dev ver. 2.0.0 (using ts-node ver. 10.9.1, typescript ver. 4.9.3)
Hello, MyService
MyService {}
Done in 2.00s.

Conclusion #

We learned how to configure the baseUrl option from scratch. If you're building an express or a GraphQL server using typescript, I believe this will help you a ton. I also created a GitHub repo to support this approach.

If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter or follow me on Twitter.

Resources #

Related Posts #

Credits: Image by Yuri from Pixabay

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle