1

I am relatively new to TypeScript and the compilation process, so please bear with me if I am missing something obvious.

I have an express API written in TypeScript using tsoa decorators to generate docs from the code.

In my app the source code is located in /src, and then transpiled to /dist at build time. tsoa automatically generates a routes file that is compiled to /dist/routes.js (tedious system btw).

The issue I am facing is that in the built routes.js file, all the controllers are referenced using the path ../src.

This causes the application to fail when running from the compiled version (which is what I'll do once in production) unless I manually change the paths to reference the compiled files instead.

For example, to make the following controller work, I have to change the import statement in routes.js from:

const LocationController_1 = require("./../src/controllers/LocationController");

to:

const LocationController_1 = require("./controllers/LocationController");

Since the routes file is generated automatically by tsoa, it should not be manually modified.

However, I have followed the instructions in the documentation for tsoa and TypeScript thoroughly and have not been able to resolve the issue. I have also researched this issue and came across, but since tsoa handles the whole process of controller discovery, I cannot force it to use an alias for the path, tsconfig-paths can be another solution but I wasn't able to configure it properly.

Is there something that I am missing?

Any guidance or suggestions would be greatly appreciated.

Here is my tsconfig.json

{
  "compilerOptions": {
    "target": "ES6",
    "module": "CommonJS",
    "lib": [
      "DOM",
      "ES6",
      "ESNext.AsyncIterable"
    ],
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "baseUrl": "./",
    "moduleResolution": "node",
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "strictPropertyInitialization": false,
    "resolveJsonModule": true
  }
}

Here's what I've tried to with aliasing paths

 "paths": {
      "@controllers/": [
        "./src/controllers/*"
      ]
    }

In tsoa.json I've tried to use the alias to find the controllers

  "controllerPathGlobs": [
    "@controllers/*"
  ],

This does not find any controller.

I've also tried to use this in tsconfig

 "paths": {
      "../src/controllers": [
        "./controllers"
      ]
    }

I'm pretty sure something obvious is missing here...!

Thank you for your help, and I apologize for any confusion or mistakes in my explanation.

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
salvob
  • 121
  • 2
  • 11

2 Answers2

2

One possible solution would be to use the tsoa configuration to point to the transpiled controllers in the dist directory.

Try and modify your tsoa.json configuration like this:

{
  "entryFile": "src/index.ts",
  "noImplicitAdditionalProperties": "throw-on-extras",
  "controllerPathGlobs": ["dist/controllers/**/*.js"],
  "spec": {
    "outputDirectory": "dist/swagger",
    "specVersion": 3
  },
  "routes": {
    "basePath": "/api",
    "routesDir": "dist/routes",
    "authenticationModule": "./src/auth/authentication"
  },
  "compilerOptions": {
    "lib": [
      "ES2015"
    ]
  }
}

In this configuration, tsoa looks for controllers in the dist/controllers directory, not src/controllers.

That setup assumes that you will always compile your TypeScript files into JavaScript before running tsoa.
The full process would be something like:

  • Compile TypeScript to JavaScript (tsc).
  • Generate routes with tsoa (npx tsoa routes).
  • Start your application (for instance, node dist/index.js).

If you need to keep your development workflow (running the app directly from TypeScript files), one option would be to have two different tsoa.json configurations - one for development (pointing to TypeScript files in src) and one for production (pointing to JavaScript files in dist). You can use NODE_ENV environment variable to choose the correct configuration.

While this is not the most convenient solution, it is a workaround that can unblock you until a better solution is found or tsoa improves its support for path aliases. Make sure to follow tsoa's issue tracker and community for updates and potential solutions.


Regarding path aliases, see "Typescript path aliases not resolved correctly at runtime"

Just spent literally hours trying to get this to work. In the end, I ended up ditching ts-node entirely and installing tsx which just worked straight out of the box.

Side note: decorators are not supported by tsx: issue 216. This is a big limitation if you're using libraries like routing-controllers and nestjs.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
0

Here is an example of how to configure path aliases in your tsconfig.json file:

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

This defines a path alias @controllers that maps to the src/controllers directory.

And you can try updating your tsoa.json file to the following:

{
  "controllerPathGlobs": ["@controllers/*"],
  ...
}

Hope this one helps you

Diego Ammann
  • 463
  • 7