21

I need modules to be resolved basing on baseUrl so output code is usable for node.js

this is my src/server/index.ts

import express = require('express');
import {port, databaseUri} from 'server/config';

...

and this is my src/server/config/index.ts

export const databaseUri: string = process.env.DATABASE_URI || process.env.MONGODB_URI;
export const port: number = process.env.PORT || 1337;

Running tsc I'm able to compile all files without erros, but output: dist/server/index.js is

"use strict";
var express = require("express");
var config_1 = require("server/config");

...

Resulting with Cannot find module 'server/config' if I'm trying to use it with node dist/sever/index.js.

Why server/config path is not resolved in any way so it would be possible to use compiled code or how to make it resolve it. Or what am I doing or thinking wrong way?

My tsc --version is 2.1.4

This is my tsconfig.json:

{
  "compileOnSave": true,
  "compilerOptions": {
      "baseUrl": "./src",
      "rootDir": "./src",
      "module": "commonjs",
      "target": "es5",
      "typeRoots": ["./src/types", ".node_modules/@types"],
      "outDir": "./dist"
  },
  "include": [
      "src/**/*"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

Note I don't want to use ../../../../relative paths.

2
  • My problem resolved when i removed outDir from tsconfig.json Commented Jan 10, 2017 at 14:06
  • 1
    but than you have cluttered src folder polluted with generated .js, .map .d.ts, instead of a common folder for all the generated files. Commented Aug 15, 2017 at 19:45

3 Answers 3

12

This post on Microsoft's typescript github explains their module resolution process. In the comments they explain that what you're trying to do can't be done.

this feature, along with the rest of the module resolution capabilities, are only to help the compiler find the module source given a module name. no changes to the output js code. if you require "folder2/file1" it will always be emitted this way. you might get errors if the compiler could not find a folder2/file1.ts, but no change to the output. https://github.com/Microsoft/TypeScript/issues/5039#issuecomment-206451221

and

The compiler does not rewrite module names. module names are considered resource identifiers, and are mapped to the output as they appear in the source https://github.com/Microsoft/TypeScript/issues/5039#issuecomment-232470330

So, the emitted JS from typescript does NOT rewrite the module path for the discovered modules you give to require. If you run your app in node after compilation (which it looks like you are with express), then it will use the node module system to resolve the module references after typescript compilation. This means that it will only respect relative paths in your module and then it will fall back to node_modules to find dependencies.

that is how it is meant to work. the compiler needs the paths to find the declaration of your module. module names are resource identifiers and should be emitted as is and not altered. https://github.com/Microsoft/TypeScript/issues/5039#issuecomment-255870508

You have basically confirmed this for yourself in the emitted output in your question.

Sign up to request clarification or add additional context in comments.

1 Comment

Although you are correct, you don't really answer the question. "module names are resource identifiers and should be emitted as is and not altered." Relative paths lead to situation where we can have unlimited number of variations of a resource identifier. Absolute paths, on the other hand, are unique identifiers, and should be the preferred way in my opinion. It seems that the only way to achieve custom (i.e. outside node_modules) absolute paths is by adding another step to the build, e.g. Webpack.
2

One way to do this is to publish your server "module" in node_modules.

On Unixen (Linux, MacOS, Solaris etc.) you can simply symlink your server folder to node_modules:

ln -s /path/to/your/project/dist/server /path/to/your/project/node_modules

This basically makes your code a library. Node will use the usual node_modules resolution when requiring and importing files.

I'm not sure how to do this on Windows because I don't use Windows.

Alternatively you can just copy the generated code to node_modules after compiling with typescript. This would work with any OS:

# Unix shell example:
cp -r dist/server node_modules

Comments

2
+100

With TypeScript, this is not possible directly.

However, if you install ttypescript (with a double t, that's not a typo) and @zerollup/ts-transform-paths, you can.

ttypescript is invoked by ttsc instead of tsc.

Then, add the ts-transform-paths plugin to your tsconfig by adding it to the compiler options:

"plugins": [
      {
        "transform": "@zerollup/ts-transform-paths",
        "exclude": ["*"]
      }
    ]

Your final tsconfig would look like this:

{
  "compileOnSave": true,
  "compilerOptions": {
      "baseUrl": "./src",
      "rootDir": "./src",
      "module": "commonjs",
      "target": "es5",
      "typeRoots": ["./src/types", ".node_modules/@types"],
      "outDir": "./dist",
      "plugins": [
        {
          "transform": "@zerollup/ts-transform-paths",
          "exclude": ["*"]
        }
      ]
  },
  "include": [
      "src/**/*"
  ],
  "exclude": [
      "node_modules",
      "**/*.spec.ts"
  ]
}

Edit: This does not work for TypeScript 4.5+.

A workaround can be found here.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.