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-paths doesn't work with node (works with ts-node) #61

Open
darkbasic opened this issue Oct 23, 2018 · 33 comments
Open

tsconfig-paths doesn't work with node (works with ts-node) #61

darkbasic opened this issue Oct 23, 2018 · 33 comments

Comments

@darkbasic
Copy link

$ node -r tsconfig-paths/register dist/index.js
module.js:550
    throw err;
    ^

Error: Cannot find module '@modules/webhooks'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._resolveFilename (/home/niko/WebstormProjects/guild-review/node_modules/tsconfig-paths/lib/register.js:73:40)
    at Function.Module._load (module.js:475:25)
    at Module.require (module.js:597:17)
    at require (internal/module.js:11:18)
    at Object.<anonymous> (/home/niko/WebstormProjects/guild-review/server/dist/index.js:5:20)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12)

Repro: https://github.com/darkbasic/guild-review
yarn && yarn workspace server build && cd server && node -r tsconfig-paths/register dist/index.js

@kel-sakal-biyik
Copy link

I have the same problem. I also tried to put tsconfig.json file under dist but didn't help.

@dotansimha
Copy link

As a workaround, you can do node -r ts-node/register -r tsconfig-paths/register dist/index.js.
@kel-sakal-biyik @darkbasic

@kel-sakal-biyik
Copy link

@darkbasic I moved a tsconfig.json file under dist folder with only path configuration and run the index.js under dist folder. By doing so it read the tsconfig file under the dist folder and it worked. You can give it a try, it might help you too.

@chanlito
Copy link

Yep just tried it not working with node, and @dotansimha solution I believe it's not optimal for production environment.

@jelling
Copy link

jelling commented Oct 30, 2018

@bushybuffalo reported a fix here. I couldn't get it to work with my project but our configuration is more complicated than the example. I went with @kel-sakal-biyik's solution for now.

@chanlito
Copy link

chanlito commented Dec 2, 2018

So I end up using the following:

"start": "node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/main.js"

Hope it doesn't have any negative impact.

@joseluisq
Copy link

joseluisq commented Jan 24, 2019

So I end up using the following:

"start": "node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/main.js"

Hope it doesn't have any negative impact.

Right, but the particularity about this temporary workaround is that I need to move ts-node to dependencies section. For example to deploy my app into a Docker container.

Ideal solution (again) would be just run the transpiled code:

{
  "prod": "node -r tsconfig-paths/register dist/main.js"
}

@sandangel
Copy link

May I ask for an update on this issue?

@manan
Copy link

manan commented Jul 21, 2019

+1

@joseluisq
Copy link

joseluisq commented Jul 22, 2019

I have created a persistent Typescript paths replacer for those wants to replace TS path aliases directly. No runtime replace.

@jeffminsungkim
Copy link

@chanlito Tried your solution, but I'm having the following error message.

EntityMetadataNotFound: No metadata for "SomeEntityClass" was found.

Any ideas?

@chanlito
Copy link

@jeffminsungkim are you using reflect-metadata? did you import or require it?

@keesvanlierop
Copy link

With node
node -r tsconfig-paths/register main.js

So this bit from the README should be removed to avoid confusion

@jeffminsungkim
Copy link

jeffminsungkim commented Oct 17, 2019

@chanlito I believe that the Nest.js framework uses reflect-metadata. So my answer is yes.

@mkalam-alami
Copy link

mkalam-alami commented Mar 15, 2020

I managed to make it work by using the TS_NODE_PROJECT env variable to point to a tweaked tsconfig file. In practice this means:

Launch script

TS_NODE_PROJECT=tsconfig.prod.json node -r tsconfig-paths/register dist/index.js

tsconfig.prod.json

{
  "extends": "./tsconfig.js",
  "compilerOptions": {
    "baseUrl": "dist"
  }
}

For some reason I could not override the compilerOptions.paths to rewrite them from the new baseUrl, but this particular setup seems OK.

@ejhayes
Copy link

ejhayes commented Apr 3, 2020

Running into this issue as well. Seems like the common solution requires changing the baseUrl value so it'll work in prod. See #114

@SkaceKamen
Copy link

SkaceKamen commented May 3, 2020

So the issue is, that the baseUrl will be resolved relative to tsconfig.json in root of your project, but in reality, it should point to your dist folder (or wherever your compiled files are). This package is working fine and it's not actually a bug, but I think adding something like TS_PATHS_ROOT environment variable, that would allow people to override the root of baseUrl would be much appreciated (actually there's already a PR for that - #114)

So the node.js is trying to load your actual typescript source files. Using the -r ts-node/register/transpile-only workaround basically means you will compile your typescript files twice because you'll be importing the typescript files (that use the paths) not the compiled javascript. It's almost the same as running ts-node on your uncompiled index file.

One possible solution is to copy tsconfig.json to your dist path and set the current working directory (CWD) to said dist path when running the file. You have to set the CWD to dist because the tsconfig.json in CWD has the highest priority.

Another possible solution (and probably much cleaner) is to use mentioned https://github.com/ilearnio/module-alias, just keep in mind you have to point to your dist folder.

Example

Project structure

tsconfig.json          - original tsconfig
src/index.ts           - your sources
dist/index.js          - tsc output
dist/tsconfig.json     - tsconfig copy next to the index.js

then you can use vscode to debug run with following config:

{
	"type": "node",
	"request": "launch",
	"name": "Launch Program",
	"skipFiles": [
		"<node_internals>/**"
	],
	"cwd": "${workspaceFolder}/dist/",
	"runtimeArgs": ["-r", "tsconfig-paths/register"],
	"program": "${workspaceFolder}\\dist\\src\\index.js",
	"outFiles": [
		"${workspaceFolder}/dist/**/*.js"
	]
}

@baba43
Copy link

baba43 commented Oct 18, 2020

@ejhayes sorry, but can you explain what you mean by that?

I'm usually specifying '.' as the baseUrl and then I get the explained error. Right now, I'm sticking with the workaround from above (#61 (comment))

@DmytroSokhach
Copy link

DmytroSokhach commented Oct 22, 2020

For me all of the above didn't work. Also had to use json5, cause have comments in tsconfig.json.
The solution from this post worked: nestjs/nest#986 (comment)

my "./tsconfig"

"outDir": "./dist",

"./tsconfig-paths-bootstrap.js" (also in the root of the project)

const json5 = require("json5");
const fs = require("fs");
const tsConfigPaths = require("tsconfig-paths");

const tsConfigPath = "./tsconfig.json";
const data = fs.readFileSync(tsConfigPath);
const tsConfig = json5.parse(data);

const paths = tsConfig.compilerOptions.paths;
tsConfigPaths.register({
  baseUrl: tsConfig.compilerOptions.outDir,
  paths: Object.keys(paths).reduce(
    (agg, key) => ({
      ...agg,
      [key]: paths[key].map(p =>
        p.replace(tsConfig.compilerOptions.baseUrl, tsConfig.compilerOptions.outDir),
      ),
    }),
    {},
  ),
});

@DmytroSokhach
Copy link

Solution above didn't work after deployment (probably more variables involved in building Docker image and environment variables etc.)
So tried with similar to #61 (comment) to actually have proper imports in the resulting *.js in "/dist" folder.
But eventually ended with "module-alias" https://www.npmjs.com/package/module-alias as it is easy to use and just works.

@tsiege
Copy link

tsiege commented Feb 4, 2021

I ended up going with a modified solution based on @mkalam-alami's approach. The issue is that the tsconfig.json at the top level sets a baseUrl that makes sense for the top level but not the compiled js in your dist/ or build/. My work around was just to copy the top level tsconfig.json into the tsc output dir and use that for the TS_NODE_PROJECT variable. That way you preserve your defaults without any custom files, and because you moved the file to that directory, you change the relative position of your baseUrl so that it again makes sense to the rest of the files you're executing. Example package.json below contrasting dev vs prod runs

  "scripts": {
    "build": "tsc && cp ./tsconfig.json ./build/",
    "start": "ts-node-dev -r tsconfig-paths/register src/index.ts",
    "start:production": "npm run build && TS_NODE_PROJECT=build/tsconfig.json node -r tsconfig-paths/register ./build/src/index.js",
  }

@g-kawin
Copy link

g-kawin commented Feb 18, 2021

Thanks, @tsiege. Your solution is awesome.
FYI. Considering the tsconfig.json at the paths section. If you define those absolute paths be like this

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

you should set the outDir to be like "./dist/src" as well.

wolfpilot added a commit to wolfpilot/demotivator-rest-api that referenced this issue May 3, 2021
wolfpilot added a commit to wolfpilot/demotivator-rest-api that referenced this issue May 3, 2021
@vilmes21
Copy link

vilmes21 commented Jul 4, 2021

Instead of

node ./dist/entry.js

use:

NODE_PATH=./dist node ./dist/entry.js

inspiration from: https://youtu.be/QVxxgEyZt9Y (TDD With TypeScript, Express, NodeJS, and Mocha Unit Tests)

@ajparrah
Copy link

TS_NODE_PROJECT=build/tsconfig.json

@tsiege Your solution is the more elegant solution while PR #114 is approved.
It's works for me. This is my full config...

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "outDir": "./dist",
    "rootDir": "./",
    "moduleResolution": "node",
    "baseUrl": ".",
    "paths": {
      "@server/*": ["./src/server/*"],
      "@globals/*": ["./src/globals/*"],
      "@plugins/*": ["./src/plugins/*"],
      "@modules/*": ["./src/modules/*"]
    },
    "esModuleInterop": true,
    "resolveJsonModule": true,
  },
  "exclude": ["node_modules", "dist", "tests"],
  "ts-node": {
    "require": ["tsconfig-paths/register"]
  }
}

Scripts on package.json. It's going to build then run build

Windows user, remember using copy instead of cp command with \\ and not /

{
...,
"scripts": {
    "dev": "cross-env NODE_ENV=dev nodemon --exec ts-node ./src/server/app.ts",
    "build": "tsc && cp ./tsconfig.json ./dist/",
    "build:windows": "tsc && copy .\\tsconfig.json .\\dist\\",
    "start": "npm run build && cross-env TS_NODE_PROJECT=dist/tsconfig.json NODE_ENV=production node -r tsconfig-paths/register ./dist/src/server/app.js",
    "start:windows": "npm run build:windows && cross-env TS_NODE_PROJECT=dist/tsconfig.json NODE_ENV=production node -r tsconfig-paths/register ./dist/src/server/app.js"
  }
}

@Ge-yuan-jun
Copy link

All above may be not elegant or convenient, I won't use these solutions because ROI is too low

@pieeee
Copy link

pieeee commented Mar 2, 2022

As a workaround, you can do node -r ts-node/register -r tsconfig-paths/register dist/index.js. @kel-sakal-biyik @darkbasic

This solved my problem

@zingerj
Copy link

zingerj commented Mar 10, 2022

You can now specify TS_NODE_BASEURL thanks to #185 as follows:

TS_NODE_BASEURL=./dist node -r tsconfig-paths/register main.js

@hungdao-testing
Copy link

hungdao-testing commented Jun 22, 2022

Hi all,
In my case, if I deleted the src folder, the issue related to alias path happens. Here is my folder structure
image

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["ES2015", "DOM"],
    "paths": {
      "@models/*": ["src/models/*"],
      "@controllers/*": ["src/controllers/*"],
      "@routes/*": ["src/routes/*"],
      "@views/*": ["src/views/*"],
      "@utils/*": ["src/utils/*"],
      "@app_type": ["typing/app.type.ts"],
      "@config/*": ["config/*"],
      "@fixture": ["fixtureData/fixture.ts"],
      "@tests/*": ["tests/*"]
    },
    "module": "commonjs",
    "baseUrl": ".",
    "esModuleInterop": true,
    "noEmitOnError": true,
    "resolveJsonModule": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "typeRoots": ["typing", "./node_modules/@types"],
    "rootDirs": ["./src", "./config"],
    "outDir": "./dist",
    "sourceMap": true
  },
  "exclude": ["node_modules", "build_script.ts"]
}

scripts in package.json

     "clean": "npx rimraf ./dist/",
    "prebuild": "npm run clean",
    "build": "npx tsc -p . && npm run build:js",
    "postbuild": "npx ts-node ./build_script.ts",
    "format": "prettier --write ./src/**/*.ts ./tests/**/*.ts",
    "start": "npx cross-env NODE_ENV=production node -r ts-node/register/transpile-only -r tsconfig-paths/register ./dist/src/server.js",

I would like to know is there a way (even work-around) to fix this issue.

@rogeraraujo90
Copy link

After some confusion with a lot of approaches to fix. I was able to fix the issue just using the env var suggested in the documentation. I hope that will help others with the same problem. I believe this is not an issue anymore.

My tsconfig.json:

{
  "compilerOptions": {
    "outDir": "./built",
    "allowJs": true,
    "target": "es6",
    "moduleResolution": "Node",
    "module": "CommonJS",
    "esModuleInterop": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "resolveJsonModule": true,
    "baseUrl": "./src",
    "paths": {
      "@config/*": ["./config/*"],
      "@controllers/*": ["./controllers/*"],
      "@models/*": ["./models/*"],
      "@repositories/*": ["./repositories/*"],
      "@services/*": ["./services/*"],
      "@tests/*": ["../tests/*"]
    }
  },
  "include": ["./src/**/*"]
}

My script to start the server:

"start": "tsc && TS_NODE_BASEURL=./built node -r tsconfig-paths/register ./built/app.js",

Current versions are:

  • Node: 16
  • tsconfig-paths: "^4.1.0",
  • typescript: "^4.7.4"

In case someone wanna confirm, that's the source code: https://github.com/rogeraraujo90/hey-freela

@abdulrahimiliasu
Copy link

So no solution for this yet basically, only workarounds for now ?

  • I wouldn't want to compile again when running start after already doing it when building

@PascalUlor
Copy link

@rogeraraujo90 your solution works only at runtime but the transpiled javascript does not have the resolved paths

@rogeraraujo90
Copy link

@rogeraraujo90 your solution works only at runtime but the transpiled javascript does not have the resolved paths

I'm not working on that project currently. By I'm using a different library in a new project and it's working. Take a look at https://github.com/benyap/resolve-tspaths

@shippu-gloitel
Copy link

tsconfig.json

"baseUrl": "./",
"paths": {
  "@/*": ["./src/*", "./build/*"] or "@/*": ["./src/*", "./dist/*"]
}

you have to change your tsconfig like above.   

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests