ts-node: tsconfig.json/paths not working with ts-node

One neat trick to use tsconfig.json/paths is to pointing the module name to your source file:

// tsconfig.json of blue-tape-fixture
{
  ...
  "paths": {
    "blue-tape-fixture": [ "src/" ]
  }
}

This way, your test files can reference the source as if it is a proper module: image You can see it is working in vscode. But it does not when I run test with ts-node:

// package.json
{
  "scripts": {
    "test": "ts-node -P tsconfig.build.json node_modules/blue-tape/bin/blue-tape \"test/**/*.ts\" | tap-spec"
  }
}

The error is:

Error: Cannot find module 'blue-tape-fixture'
    at Function.Module._resolveFilename (module.js:325:15)
    at Function.Module._load (module.js:276:25)
    at Module.require (module.js:353:17)

You can see it here: https://github.com/unional/blue-tape-fixture/tree/ts-node

# clone
npm install
npm test

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 153
  • Comments: 48 (16 by maintainers)

Commits related to this issue

Most upvoted comments

Instead of the PR, I have now created the tsconfig-paths package that makes it possible to automatically resolve paths during execution with ts-node, node, or mocha. Just follow the instructions in the readme.

@jonaskello You saved my ass here!

Is there any reason why this shouldn’t become a default built in part of ts-node? It seems like it would make more sense to include this by default, than to not.

Note to all using @jonaskello 's tsconfig-paths:

The errror “Missing paths in compilerOptions. tsconfig-paths will be skipped” means that you don’t have any paths property specified in your tsconfig.json. I had been able to use imports relative to my src directory just by specifying "baseUrl": ".", but to get ts-node/node/mocha to understand the same imports, I also needed to specify a paths property in my tsconfig.json, eg:

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

Hope this helps another overwhelmed soul.

maybe my workaround will help:

  1. install required plugins: npm i -D ttypescript typescript-transform-paths ts-node tsconfig-paths. these are packages that will help us to transform the paths.

  2. then, on tsconfig.json, i put:

    {
     "ts-node": {
       "transpileOnly": true,
       "require": [  // set this so you dont need to use ts-node -r 
     	"typescript-transform-paths/register",
     	"tsconfig-paths/register"
        ]
     },         
     "compilerOptions": {
        "composite": true,
        "rootDir": ".", // must define
        "baseUrl": "src", // must define, the paths will relative to this
        "outDir": "lib", 
        "skipLibCheck": false,
        "paths": {
     	"@app/*": ["./*"],
     	"@controllers/*": ["./controllers/*"],
        },
         "plugins": [
     	  { "transform": "typescript-transform-paths" }
         ]
     }
    }
    
  3. then we can use this on our codes everywhere:

    import myControllers from "@controllers/main.ts"
    
  4. then to compile, we need to run npx ttsc -p tsconfig.json , we use npx so we dont need to install ttypescript globally

  5. and to run on ts-node, we can simply run npx ts-node -p tsconfig.json src/app.ts, also npx for ts-node.

My conclusion: To workaround with ts-node paths, we need tsconfig-paths required on ts-node runtime. but on production we just need to compile them into absolute path, so we use ttypescript and typescript-transform-paths to compile and transform the module paths to absolute path. then the program can work fine with node without registering tsconfig-paths or any plugins like node lib/index.js

I hope this solution will help, also sorry if my word kinda messed up, i try to explain it as simple as possible.

@ashok-sc ts-node has no support for paths in tsconfig.json, and no plans to add it. I think your best bet to get it working is using tsconfig-paths. If you have trouble using it feel free to file an issue at that repo.

If you are using webpack the scenario is quite different. If you are using ts-loader you might want to try tsconfig-paths-webpack-plugin altough it is still early in development. If you are using awesome typescript loader then it has this type of plug-in built-in.

Clearly I’m a weirdo. This is my fourth time finding this thread, but it doesn’t appear to get much activity. It’s probably because I use mono-repos.

For future me coming back here, this is the link: https://www.npmjs.com/package/tsconfig-paths

@joseluisq That doesn’t address the issue in any possible way. People here want to run typescript code directly with a support of paths aliases from tsconfig.json for the dev purposes and not only. Specifically I am facing the issue of wrong paths resolution when outDir is specified in tsconfig.json.

By the way, there is already a proven solution to the problem you referenced https://github.com/ilearnio/module-alias or https://github.com/dividab/tsconfig-paths or even for webpack https://github.com/dividab/tsconfig-paths-webpack-plugin

@jonaskello You saved my ass here!

Is there any reason why this shouldn’t become a default built in part of ts-node? It seems like it would make more sense to include this by default, than to not.

Apparently I’ve been through this before… lol.

This really probably should become default behavior.

Does anyone have an idea on how to work around this issue when using ESM? I am normally using node --loader ts-node/esm <path> to start scripts but I could not get it to work using any of the solutions proposed here.

Oh boy. This looks like it’s going to be fun to figure out.

with baseUrl enabled it seems @jonaskello’s plugin will also use this for npm_modules that otherwise would load normally. When removing baseUrl and paths all together and using relative paths the project compiles again.

$ npm run test

> xxxxxx@1.0.0 test /Users/xvilo/projects/xxxxxx
> mocha -r ts-node/register -r tsconfig-paths/register --require tests/testHelper.js tests/js/**/*.spec.ts

Error: Cannot find module '/Users/xvilo/projects/xxxxxx/src/js/util'
    at Function.Module._resolveFilename (module.js:543:15)
    at Function.Module._resolveFilename (/Users/xvilo/projects/xxxxxx/node_modules/tsconfig-paths/lib/register.js:29:44)
    at Function.Module._load (module.js:470:25)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/xvilo/projects/xxxxxx/node_modules/tough-cookie/lib/memstore.js:35:12)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/xvilo/projects/xxxxxx/node_modules/tough-cookie/lib/cookie.js:36:25)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/xvilo/projects/xxxxxx/node_modules/jsdom/lib/api.js:5:21)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/Users/xvilo/projects/xxxxxx/tests/testHelper.js:1:13)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
    at Module.require (module.js:593:17)
    at require (internal/module.js:11:18)
    at requires.forEach.mod (/Users/xvilo/projects/xxxxxx/node_modules/mocha/bin/_mocha:511:3)
    at Array.forEach (<anonymous>)
    at Object.<anonymous> (/Users/xvilo/projects/xxxxxx/node_modules/mocha/bin/_mocha:510:10)
    at Module._compile (module.js:649:30)
    at Object.Module._extensions..js (module.js:660:10)
    at Module.load (module.js:561:32)
    at tryModuleLoad (module.js:501:12)
    at Function.Module._load (module.js:493:3)
    at Function.Module.runMain (module.js:690:10)
    at startup (bootstrap_node.js:194:16)
    at bootstrap_node.js:666:3
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! xxxxxx@1.0.0 test: `mocha -r ts-node/register -r tsconfig-paths/register --require tests/testHelper.js tests/js/**/*.spec.ts`
npm ERR! Exit status 1
npm ERR! 
npm ERR! Failed at the xxxxxx@1.0.0 test script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/xvilo/.npm/_logs/2018-06-21T15_25_59_483Z-debug.log

and with baseUrl and paths disabled:

$ npm run test

> xxxxxx@1.0.0 test /Users/xvilo/projects/xxxxxx
> mocha -r ts-node/register -r tsconfig-paths/register --require tests/testHelper.js tests/js/**/*.spec.ts

Missing baseUrl in compilerOptions. tsconfig-paths will be skipped


  Dom.createNodeFromString
    ✓ Div with class
    ✓ span with class
    ✓ img
    ✓ table with 1 tr and 1 td with content
    ✓ ul
    ✓ li
    ✓ ul with li


  7 passing (22ms)

part of my package.json

"scripts": {
    "test": "mocha -r ts-node/register -r tsconfig-paths/register --require tests/testHelper.js tests/js/**/*.spec.ts"
  },

Okay, so I found a solution that works reasonably well for my use-case. I needed this just for Knex’s knexfile.ts and couldn’t find a solution

Constraints:

  • Every “path” in paths I have has only 1 item in the array
  • I am able to use module-alias as a dev dependency
  • I have only 1 file that requires this fix, however putting this in a fix-paths.ts file works if it is is imported first
  • I am able to use "resolveJsonModule": true

Code

import moduleAlias from 'module-alias';
import * as path from 'path';
import { compilerOptions } from './tsconfig.json';

const root = path.join(__dirname, compilerOptions.baseUrl || '');

for (const [key, paths] of Object.entries(compilerOptions.paths)) {
  const target = path.join(root, paths[0]);
  moduleAlias.addAlias(key, target);
}

For a solution you can use today, see #1450

Path mapping is being added as a built-in feature of ts-node in an upcoming release. To follow progress, see #1585

Thanks @jonaskello!

It also seems to work when using ts-node through nyc:

nyc.config.js

module.exports = {
  all: false,
  exclude: ['**/*.d.ts', '**/*.test*.ts', '**/index.ts'],
  extension: ['.ts'],
  include: ['src/**/*.ts'],
  reporter: ['text-summary'],
  require: ['tsconfig-paths/register', 'ts-node/register'],
};

Here’s my tsconfig.json:

{
  "compilerOptions": {
    "outDir": "./compiled/",
    "sourceMap": true,
    "noImplicitAny": false,
    "module": "commonjs",
    "lib": ["es6", "dom", "esnext"],
    "target": "es6",
    "jsx": "react",
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "baseUrl": "src",
    "paths": {
      "@src/*": [
        "*"
      ]
    }
  },
  "include": [
    "./src/core/*",
    "./src/client/*",
    "./src/server/*"
  ]
}

Here’s a gist of what a webpack config should look like with awesome-typescript-loader’s tsconfig paths plugin. I don’t pass anything in the constructor in my config, but maybe you need it if your tsconfig.json is in a non-standard location.

var TsConfigPathsPlugin = require('awesome-typescript-loader').TsConfigPathsPlugin;

module.exports = {
	entry: ...,
	output: ...,
	resolve: {
		extensions: ['...'],
		plugins: [
			new TsConfigPathsPlugin()
		]
	}
}

@shirakaba Just a note, you can set your "baseUrl" to "./src/" and "paths" like this

"paths": {
  "*" : ["./*"]
}

I will be the same, but you are able to add more paths with the same root more easily.