Typescript paths not working in an Express project
Asked Answered
P

7

55

I am trying to use TypeScript's paths functionality so that I don't need to use relative imports any more.

Here is my tsconfig.json file:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "outDir": "./dist",
    "rootDir": ".",
    "moduleResolution": "node",
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "baseUrl": ".",
    "allowJs": true,
    "paths": {
      "*": ["node_modules/*", "src/*"],
      "@config/*": ["src/config/*"],
      "@controllers/*": ["src/controllers/*"],
      "@middlewares/*": ["src/middlewares/*"],
      "@models/*": ["src/models/*"],
      "@routes/*": ["src/routes/*"],
      "@types/*": ["src/types/*"],
      "@utils/*": ["src/utils/*"]
    }
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "firebase-config.json", "webpack.config.js"]
}

Here is my package.json file:

{
  "name": "express-ts-boilerplate",
  "version": "0.1.0",
  "description": "Express Typescript Boilerplate",
  "main": "src/server.js",
  "author": "Sriram R",
  "scripts": {
    "start": "NODE_ENV=production node dist/src/app.js",
    "dev": "nodemon src/app.ts",
    "build": "tsc -p .",
    "test": "mocha --exit -r ts-node/register src/tests/*.spec.ts"
  },
  "dependencies": {
    // Dependencies here
  },
  "devDependencies": {
    // Dependencies here
  },
}

So now in one of my files, I try @config/typeConfig but I just get cannot find module error.

Maybe it's because of nodemon but it didn't work with ts-node too. How can I get this to work?

Possessory answered 1/10, 2019 at 14:34 Comment(6)
"So now in one of my files". Which file? Where is it located?Bigot
It is located under src folder. The server file where I'm importing config variables.Possessory
Weird. I tried to replicate your problem and it's working fine here. How come you have nodemon src/app.ts?Bigot
Because I'm using nodemon to run during development. That's where I suspect the problem is.Possessory
Shouldn't it be nodemon dist/src/app.js?Bigot
No. That will only work after building the ts files. During testing, I don't want to keep it building every time and nodemon works fine with typescript express projects.Possessory
B
115

Note: for a working example with nodemon, skip to the second section of my answer.

If you mean that once you compiled the files and run the application, the modules are not found, then have a look at this thread: Module path maps are not resolved in emitted code

"paths" is designed for use with loaders that allow remapping

Say I have this path in my tsconfig.json:

"paths": {
      "@config/*": ["src/config/*"]
    }

And I require a file using that path in a file

import test from '@config/test';

Looking into the compiled file, I end up with

var test_1 = __importDefault(require("@config/test"));

As you can see, paths have not been resolved, it's still @config/test. The same thing will happen when testing your app with nodemon and ts-node.

In addition, you need to use a Typescript path alias resolver, like for exampletspath.

The TypeScript compiler will be able to resolve the paths so this will compile without problems, however the JavaScript output will not be possible to execute by Node nor a Web Browser, why? the reason is simple!

The JavaScript engine does not know anything about the compile time TypeScript configuration.

In order to run your JavaScript code, the path aliases now needs to be made into relative paths again, here is when TSPath comes into play.


That being said, if you want to make things work with nodemon, the following configuration will do. Beforehand, make sure you installed tsconfig-paths.

npm i tsconfig-paths

Use this to load modules whose location is specified in the paths section of tsconfig.json. Both loading at run-time and via API are supported. (...) If you require this package's tsconfig-paths/register module it will read the paths from tsconfig.json and convert node's module loading calls into to physcial file paths that node can load.

Perfect, we will execute node with -r tsconfig-paths/register to convert paths into physical file paths and -r ts-node/register to execute ts files on the fly and nodemon will restart the app upon changes.

In your package.json, you need to add this (modify it as needed):

    "nodemonConfig": {
          "ignore":
            [
              "**/*.test.ts",
              "**/*.spec.ts",
              ".git",
              "node_modules"
            ],
          "watch": [
            "src"
          ],
          "exec": "node -r tsconfig-paths/register -r ts-node/register ./src/server.ts",
          "ext": "ts, js"
        },
    "scripts": {
          "dev": "nodemon"
        }

Note the added configuration for nodemon.

And finally

npm run dev

And things should be running smoothly.

Bigot answered 3/10, 2019 at 20:13 Comment(1)
so hard to find this. Truely safe meDefinitely
H
32

jperl's answer is completely correct.

In case you want a one-line solution:

nodemon -e ts,js --exec ts-node -r tsconfig-paths/register ./src/server.ts

Just remember to install tsconfig-paths/register:

npm i -D tsconfig-paths

In case instead of requiring -r tsconfig-paths/register in a CLI command or an npm script you would like to require it in ts-node configuration, you could do it in tsconfig.json as follows:

// in tsconfig.json
{
  // ... other TypeScript configuration
  "ts-node": {
    "require": ["tsconfig-paths/register"]
  }
}
Hebraic answered 6/11, 2020 at 15:3 Comment(6)
Thanks for the answer , but you had better mention we have to install tsconfig-paths.Hiero
Thanks for the feedback. I will edit my answerHebraic
Should it say: npm i -D tsconfig-paths instead of npm i -D tsconfig-paths/register ?Mangonel
absolutely true! i will fix it.Hebraic
it dos't work for meLandmass
Damn, this is convoluted. Thanks!Fahey
J
3

In my particular case use "tsc-alias" these were my steps:

  1. Install package npm install --save-dev tsc-alias
  2. Change the command with which I compile in package.json to "build": "tsc && tsc-alias"
  3. Modify my tsconfig.json because I did not have the outDir, so that it would look like this:
{
   "compilerOptions": {
      "outDir": "miniprogram",
      "baseUrl": "miniprogram",
      "paths": {
       "lib / *": ["./lib/*"]
     },
...
}

Note: If I don't add the outDir it gives me the following error: "compilerOptions.outDir is not set"

Then when importing it I do: import {Util} from "lib/my/path/util";

Jewelry answered 15/7, 2021 at 21:4 Comment(0)
D
2

first step. we need to install tsconfig-paths

npm i -D tsconfig-paths

second step. Create the nodemon.json file in the root path. same level with package.json

third step. Copy and paste the code below into the nodemon.json file. In the code, ./src/app.ts This part is an express execution point. Modify it according to your situation.

{
  "ignore": ["**/*.test.ts", "**/*.spec.ts", ".git", "node_modules"],
  "watch": ["src"],
  "exec": "node -r tsconfig-paths/register -r ts-node/register ./src/app.ts",
  "ext": "ts, js"
}

last step. write executing script code in the package.json file

"script": {
  "dev": "nodemon"
}
Der answered 30/3, 2023 at 20:6 Comment(0)
L
0

Development

npm i -save-dev tsconfig-paths/register

tsconfig.json

{
 "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@src/*": ["src/*"],
    },   
  }
}

package.json

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

Build

npm i -save-d ttypescript @zerollup/ts-transform-paths

tsconfig.json

{
 "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@src/*": ["src/*"],
    },   
  }
 "plugins": [
      {
          "transform": "@zerollup/ts-transform-paths",
      }
  ],
}

package.json

"scripts": {
  build: "ttsc -P ./tsconfig.json"
}
Lentha answered 12/3, 2021 at 0:52 Comment(0)
L
0

TL;DR: delete all .js files

For those who didnt manage the with correct solutions above:

With my project I had 'leftover' .js files created (at some point in the past) under each .ts file. running nodemon (which in turn should use tsc) did not overwrite those files, and I kept getting the same require stack errors with Cannot resolve module.

Removing all .js files fixed it for me.

Refer to this answer for more information on how to actually do it in a safe(ish) way: Find (and delete) all files with a specified extension. make sure you actually review the list of files before deleting them.

Lightheaded answered 1/2, 2022 at 12:50 Comment(0)
B
0

In my case it didn't work any of the last answers so I had to install [tsx] and create a nodemon.json file with the next configuration

npm i tsx
{
    "ignore": ["**/*.test.ts", "**/*.spec.ts", ".git", "node_modules"],
    "watch": ["."],
    "exec": "tsx index.ts",
    "ext": "ts, js"
}

and then in the package.json add the following

"scripts": {
  "dev": "npx nodemon --config nodemon.json"
}

and the npm run dev

Basketwork answered 15/12, 2023 at 6:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.