How to Configure Typescript baseUrl in a Node.js Project
Jasser Mark Arioste
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