Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tsconfig.json/paths not working with ts-node #138

Closed
unional opened this issue Jun 19, 2016 · 48 comments · Fixed by rootstrap/node-ts-api-base#1
Closed

tsconfig.json/paths not working with ts-node #138

unional opened this issue Jun 19, 2016 · 48 comments · Fixed by rootstrap/node-ts-api-base#1
Labels
external research Needs design work, investigation, or prototyping. Implementation uncertain.

Comments

@unional
Copy link
Contributor

unional commented Jun 19, 2016

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
@blakeembrey
Copy link
Member

@unional That's the node.js error - TypeScript is working fine, but node will never be able to resolve an alias like that unless TypeScript emits code that rewrites paths. What do you think is the solution here?

@unional
Copy link
Contributor Author

unional commented Jun 19, 2016

I see. In order for it to work, a module-path-rewriter need to be written and loaded by ts-node.
Alternatively is to load the transpiled code dist/*, which kind of defeat the purpose of ts-node (I said kind of because the test files, in this use case, can remain as ts files).

@blakeembrey
Copy link
Member

This module uses the emitted code though - it's TypeScript itself that doesn't do any rewriting right?

@unional
Copy link
Contributor Author

unional commented Jun 20, 2016

Just check. Nope it does not do any rewriting. Seems like the baseUrl and paths is only used during compilation. By design or bug on TS side?

@unional
Copy link
Contributor Author

unional commented Jun 20, 2016

Updated https://github.com/unional/blue-tape-fixture/tree/ts-node to demo the issue.
run npm run build-test and see under dist/test/index.ts. It is still requiring blue-tape-fixture

@unional
Copy link
Contributor Author

unional commented Jun 20, 2016

Confirm above statement: microsoft/TypeScript#5039 (comment)

@blakeembrey
Copy link
Member

@unional Yeah, it's tricky. I can understand TypeScript's stance, if they don't have a solution for it built-in I think we can investigate adding a plugin once they implement the pluggable transforms in TypeScript 2.0. This is definitely more of a user-land feature.

@blakeembrey blakeembrey added the research Needs design work, investigation, or prototyping. Implementation uncertain. label Jul 23, 2016
@sanex3339
Copy link

any news? i want to use 'paths' option in my tests

@blakeembrey
Copy link
Member

blakeembrey commented Oct 2, 2016

No, it does not work and is not expected to work. Someone can still implement a plugin (which would be very valuable to others too!), but I am not currently working on it.

@jonaskello
Copy link
Contributor

jonaskello commented Dec 26, 2016

Maybe this could be solved by augmenting node's loading rather than having typescript re-write the paths. There are some alternatives mentioned here. In particular I'm thinking that wrapping the global require and just changing the path according to tsconfig would be the simplest solution.

@jonaskello
Copy link
Contributor

When I looked closer I realised that wrapping global require is not possible in a way that replaces it (the example above installs a separate require function). However it is possible to patch Module._load like is done in mock-require. I did some experiments with this and it seems doable. I'll try to put together a PR to demonstrate.

@jonaskello
Copy link
Contributor

For those interested I did a PR to enable execution of projects with tsconfig paths in #254.

@jonaskello
Copy link
Contributor

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.

@shirakaba
Copy link

shirakaba commented Apr 24, 2017

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.

@michaeljota
Copy link

@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.

@ashok-sc
Copy link

ashok-sc commented Dec 5, 2017

I've tried nearly all the above solutions and I'm still getting Module not found: Error: Can't resolve ....

What's the solution here? I have updated my tsconfig.json webpack.config.js and even tried tsconfig-paths. None of these work.

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

@jonaskello
Copy link
Contributor

jonaskello commented Dec 5, 2017

@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.

@michaeljota
Copy link

@ashok-sc As @jonaskello said, there is no plan to support path, as you need to replace the path call with the proper full path in order to be understandable for Webpack. You could use Awesome Typescript Loader that have a plugin out-the-box for that, but still, it needs to be a plugin.

@ashok-sc
Copy link

ashok-sc commented Dec 5, 2017

Hey @jonaskello and @michaeljota thanks for the help! I am in fact using awesome-typescript-loader with webpack. However, the instructions are quite poor. I understand that you may not have the answers here, but I thought I'd give it a shot anyway.

The instructions state to add the TsConfigPathsPlugin, but it's not clear as to what it needs in the constructor. Here's what I tried:

new TsConfigPathsPlugin({
    configFileName: path.join(__dirname, './tsconfig.json'),
    compiler: 'typescript'
  })

This doesn't seem to work though and I still get module not found.

Anyway, if you don't have the answer of the top of your head feel free to ignore.

@jonaskello
Copy link
Contributor

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()
		]
	}
}

@jonaskello
Copy link
Contributor

@ashok-sc If it does not work, you can try version 0.2.0 of tsconfig-paths-webpack-plugin. I have added code that prints the path that it tries to load the tsconfig.json from.

Note, tsconfig-paths-webpack-plugin is used instead of the one in awesome-typscript-loader. You can also use it with ts-loader.

@joseluisq
Copy link

joseluisq commented Jul 8, 2019

@alexeychikk this thread confirms that the maintainer is not interested in any implementation of TS paths support, but he suggests external implementations instead as you have enumerated.

Sure, if the people wants to run TS code directly via ts-node is dividab/tsconfig-paths an alternative . I use it for development.

My solution is pretty simple: replace TS path aliases using a tsconfig.json as well. But replacing those paths directly into the .js files, not on the fly like tsconfig-paths for example.

@SephReed
Copy link

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

@viT-1
Copy link

viT-1 commented Aug 8, 2019

@alexeychikk

  1. module-alias not the best way if you use es6
    Not working with native ES modules ilearnio/module-alias#59
  2. If project doesn't use webpack "even webpack" is not usecase.
  3. May be you can help me to configure tsconfig-paths to use it as npm script with ts-node for script.ts and extended tsconfig containing outDir?
    Bug with extends property in tsconfig dividab/tsconfig-paths#39

@SephReed
Copy link

SephReed commented Dec 4, 2019

@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.

@bennycode
Copy link

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'],
};

mattwynne added a commit to SmartBear/git-en-boite that referenced this issue Aug 4, 2020
See TypeStrong/ts-node#138

This allows us to use custom type declarations and have the compilers
work consistently between tsc, ts-node, mocha and cucumber

It does mean we'll need to remember to add the require for
tsconfig-paths in a couple of other places, probably, like where we use
mocha.

Closes #151
@talwrii
Copy link

talwrii commented Aug 13, 2020

Thank you to janaskello for tsconfig-paths a slight annoyance I have is that it seems like tsconfig-paths needs to be installed in projects themselves for ts-node -r tsconfig-paths/register to work - which is a bit of a pain for third party libraries (my use case of understanding someone else code is perhaps unusual).

I'd also like to say that on newer versions of node you get a MODULE_NOT_FOUND error (other page about this suggest deleting and reinstalling things for this). It's odd how ts-node in one says can "find" the library (because if a file does not exist you get a different error) but then fails to import.

I would vote for ts-node refusing to run if paths is set given that this error is a little cryptic (I didn't find this page until I guessed that the problem might be because ts-node is ignoring paths and googled this - working in someone elses repo).

@blephy
Copy link

blephy commented Oct 2, 2020

I was running on the same issue when running webpack with ts-node (i'm using Typescript language webpack configuration) but already followed the webpack documentation and installed tsconfig-paths.

Just putting "moduleResolution": "node" into my tsconfig.webpack.json resolved the issue.

Hope this help

@SephReed
Copy link

@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.

@rachaeldawn
Copy link

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);
}

@SephReed
Copy link

SephReed commented Jul 27, 2021

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

@fatihaziz
Copy link

fatihaziz commented Sep 24, 2021

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.

@puchm
Copy link

puchm commented Nov 1, 2021

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.

@danielo515
Copy link

@fatihaziz you answer saved my life, thanks!

@droplessdeclan
Copy link

@puchm Did you ever manage to find a solution to this? I'm having the same issue

@cspotcode
Copy link
Collaborator

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external research Needs design work, investigation, or prototyping. Implementation uncertain.
Projects
None yet
Development

Successfully merging a pull request may close this issue.