tsconfig-paths icon indicating copy to clipboard operation
tsconfig-paths copied to clipboard

paths are not being rewritten after compilation

Open mdbr000-np opened this issue 2 years ago • 10 comments

No matter what I seem to try, the values defined in paths in my tsconfig.json file are not being transformed by tsconfig-paths, which results in node being unable to resolves any modules.

Giving an example, where I would expect @graphql-handlers imports in my ts files to be converted to graphql-handlers in my compiled .js... but when you examine the output in the dist folder, all of the paths still show @graphql-handlers which renders node unable to run.

tsconfig.json

// https://www.typescriptlang.org/tsconfig
{
  "compilerOptions": {
    "target": "ES6",
    "moduleResolution": "node",
    "baseUrl": "src",
    "esModuleInterop": true,
    "outDir": "dist",
    "sourceMap": true,
    "noEmit": false,
    "paths": {
      "@graphql-handlers": [ "graphql-handlers" ],
    }
  },
  "include": [
    "src"
  ],
  "exclude": ["node_modules"],
  "typeRoots": [
    "src/@types",
  ]
}

package.json

{
  "name": "xxxxxxx",
  "version": "2.0.0",
  "description": "xxxxxxxxxxxx",
  "main": "src/index.js",
  "scripts": {
    "compile": "rm -rf ./dist; tsc",
    "boot": "node dist/src/index.js",
    "watch": "tsc-watch --onSuccess \"npm run boot\"",
    "test": "node node_modules/.bin/jest --coverage"
  },
  "type": "module",
  "author": "xxxxxxxxxxxx",
  "license": "UNLICENSED",
  "dependencies": {
    "apollo-server-core": "^3.10.0",
    "apollo-server-express": "^3.10.0",
    "bcryptjs": "^2.4.3",
    "express": "^4.18.1",
    "express-graphql": "^0.12.0",
    "express-jwt": "^7.7.5",
    "graphql": "^15.8.0",
    "jsonwebtoken": "^8.5.1",
    "oracledb": "^5.4.0"
  },
  "devDependencies": {
    "@babel/core": "^7.18.6",
    "@babel/preset-env": "^7.18.6",
    "@babel/preset-typescript": "^7.18.6",
    "@faker-js/faker": "^7.3.0",
    "@types/express": "^4.17.13",
    "@types/jest": "^28.1.6",
    "@types/oracledb": "^5.2.3",
    "@typescript-eslint/eslint-plugin": "^5.30.6",
    "@typescript-eslint/parser": "^5.30.6",
    "babel-jest": "^29.0.3",
    "eslint": "^8.19.0",
    "eslint-config-airbnb-base": "^15.0.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-jest": "^26.5.3",
    "jest": "^28.1.2",
    "supertest": "^6.2.4",
    "ts-node": "^10.9.1",
    "tsc-watch": "^5.0.3",
    "tsconfig-paths": "^4.1.0",
    "typescript": "^4.7.4"
  }
}

index.ts

import { bootServer } from './server.js';
import resolver from '@graphql-handlers/login/resolvers.js';
import loginTypes from '@graphql-handlers/login/schema.js';
import types from '@graphql-handlers/types.js';
import centerOutcomeSchema from '@graphql-handlers/centerOutcomes/schema.js';

const port = process.env.PORT;
const dbConn = null;
bootServer([types, loginTypes, centerOutcomeSchema], [resolver], port, dbConn);

Run command: rm -rf dist; npm run compile; node_modules/.bin/ts-node -r tsconfig-paths/register dist/index.js

Error output:

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@/graphql-handlers' imported from /app/api/dist/index.js                           
Did you mean to import /app/api/dist/graphql-handlers/login/resolvers.js?                                                             
    at new NodeError (node:internal/errors:388:5)                                                                                     
    at packageResolve (node:internal/modules/esm/resolve:910:9)    
    at moduleResolve (node:internal/modules/esm/resolve:959:20)
    at defaultResolve (node:internal/modules/esm/resolve:1174:11)  
    at ESMLoader.resolve (node:internal/modules/esm/loader:605:30) 
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:318:18)                                                                   at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:80:40)                                                            
    at link (node:internal/modules/esm/module_job:78:36) {         
  code: 'ERR_MODULE_NOT_FOUND'                                                                                                        
}                                      

Looking at the compiled output in dist/index.js, @graphql-handlers has not been converted:

import { bootServer } from './server.js';
import resolver from '@graphql-handlers/login/resolvers.js';
import loginTypes from '@graphql-handlers/login/schema.js';
import types from '@graphql-handlers/types.js';
import centerOutcomeSchema from '@graphql-handlers/centerOutcomes/schema.js';
const port = process.env.PORT;
const dbConn = null;
bootServer([types, loginTypes, centerOutcomeSchema], [resolver], port, dbConn);
//# sourceMappingURL=index.js.map

mdbr000-np avatar Oct 04 '22 22:10 mdbr000-np

This package doesn't affect TypeScript compilation, and therefore the module paths are left as-is in the final compiled JavaScript. If you need to convert these (e.g. are unable to use the registration described below), you need to use a different solution.

However, you can register the paths in runtime via this package by altering the scripts in your package.json that run the node process to include the flag -r tsconfig-paths/register. For example, changing your boot-script to be node -r tsconfig-paths/register dist/src/index.js should resolve your issue.

Defrosted avatar Oct 07 '22 13:10 Defrosted

For some reason, even registering tsconfig-paths/register while calling the script via node is not working for me (still throws error about not finding the "pathed" modules). However, running via ts-node does work as expected (via registration in tsconfig.json).

"outDir": "./dist",
"baseUrl": "./src",
"paths": {
  "@services/*": ["./services/*"],
},
"ts-node": {
  "require": ["tsconfig-paths/register"]
}
> node -r tsconfig-paths/register dist/src/index.js

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module '@services/randomService'
Require stack:
- /<PATH>/dist/src/index.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._resolveFilename (/<PATH>/node_modules/tsconfig-paths/lib/register.js:103:40)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/<PATH>/dist/src/index.js:4:27)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/<PATH>/dist/src/index.js'
  ]
}

kendallroth avatar Oct 07 '22 14:10 kendallroth

Try setting TS_NODE_BASEURL=./dist env when running node...

rgskyblue avatar Oct 10 '22 05:10 rgskyblue

For some reason, even registering tsconfig-paths/register while calling the script via node is not working for me (still throws error about not finding the "pathed" modules). However, running via ts-node does work as expected (via registration in tsconfig.json).

"outDir": "./dist",
"baseUrl": "./src",
"paths": {
  "@services/*": ["./services/*"],
},
"ts-node": {
  "require": ["tsconfig-paths/register"]
}
> node -r tsconfig-paths/register dist/src/index.js

node:internal/modules/cjs/loader:936
  throw err;
  ^

Error: Cannot find module '@services/randomService'
Require stack:
- /<PATH>/dist/src/index.js
    at Function.Module._resolveFilename (node:internal/modules/cjs/loader:933:15)
    at Function.Module._resolveFilename (/<PATH>/node_modules/tsconfig-paths/lib/register.js:103:40)
    at Function.Module._load (node:internal/modules/cjs/loader:778:27)
    at Module.require (node:internal/modules/cjs/loader:1005:19)
    at require (node:internal/modules/cjs/helpers:102:18)
    at Object.<anonymous> (/<PATH>/dist/src/index.js:4:27)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12) {
  code: 'MODULE_NOT_FOUND',
  requireStack: [
    '/<PATH>/dist/src/index.js'
  ]
}

@kendallroth That would seem to mean that the plugin is unable to access the tsconfig.json-file when you're running Node. You should probably copy it into your dist/ folder (incorporate it into your build script) in order for Node to find it when you're launching your application.

Defrosted avatar Oct 10 '22 06:10 Defrosted

Ah, that is an excellent point, and I know that the TS config file was certainly not being copied during the build. However, we eventually decided to go with an approach during build step, simply to avoid having to have any typescript references or packages in the production environment. However, thanks for the answer, and I hope it can help someone else in the future!

kendallroth avatar Oct 10 '22 14:10 kendallroth

@kendallroth What approach did you take? I'm suffering from the same issue and at this point, I'm planning to just use ts-node in production.

TriStarGod avatar Oct 10 '22 20:10 TriStarGod

I used resolve-tspaths as part of the build step (ie. "build": "tsc && resolve-tspaths").

kendallroth avatar Oct 11 '22 13:10 kendallroth

I used resolve-tspaths as part of the build step (ie. "build": "tsc && resolve-tspaths").

This was the easiest and most straight forward solution for my needs. Thanks @kendallroth !

Beadle85 avatar Dec 07 '22 20:12 Beadle85

@kendallroth big thx

polioan avatar Jan 04 '23 17:01 polioan

i was having this issue and this comment https://github.com/dividab/tsconfig-paths/issues/222#issuecomment-1272791309 resolved in conjunction with TS_NODE_PROJECT

we use: TS_NODE_BASEURL=dist/src/ TS_NODE_PROJECT=tsconfig.json node -r tsconfig-paths/register dist/src/index

mikegwhit avatar Aug 07 '24 20:08 mikegwhit