简体   繁体   中英

paths from tsconfig.json doesn't work after tsc

In my Express project, I import from paths like @common/foo . Thanks to paths in tsconfig.json , it's just an alias to ../common/src/foo . That's awesome and works in development with this script in nodemon.json :

{
    "watch": ["src", "../common/src"],
    "ext": "ts",
    "ignore": ["src/public"],
    "exec": "ts-node -r tsconfig-paths/register src/index.ts"
  }

The problem is that I can't make it work in production mode.

I build the project with tsc , and if I inspect the generated files, they import stuff from @common/ and not from ../common/src/ . At first I thought it's fine, since tsconfig-paths works in runtime, so I just need to include it in the start script as such:

node -r tsconfig-paths/register dist/index.js

Unfortunately it didn't work, and I get those Cannot find module '@common/foo error messages in console.

What's the problem? Did i configured it wrong?


My package.json (dropped all irrelevant parts):

{
  "main": "index.js",
  "scripts": {
    "start": "cross-env NODE_ENV=prod node dist/index.js",
    "build": "rimraf ./dist/ && cross-env NODE_ENV=prod tsc"
  },
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "@types/express": "^4.17.4",
    "@types/node": "^13.11.0",
    "cross-env": "^6.0.3",
    "rimraf": "^3.0.2",
    "ts-node": "^8.8.2",
    "tsconfig-paths": "^3.9.0",
    "typescript": "^3.8.3"
  }
}

My tsconfig.json (dropped all irrelevant parts):

{
  "compilerOptions": {
    "module": "commonjs",
    "baseUrl": "./",
    "outDir": "dist",
    "experimentalDecorators": true,
    "allowSyntheticDefaultImports": true,
    "esModuleInterop": true,
    "noImplicitAny": false,
    "target": "es6",
    "emitDecoratorMetadata": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "types": [
      "node"
    ],
    "typeRoots": [
      "node_modules/@types"
    ],
    "paths": {
      "@common/*": [
        "../common/src/*"
      ]
    }
  },
  "include": [
    "./src/**/*.ts"
  ],
  "exclude": [
    "./src/dist/"
  ],
  "references": [
    {
      "path": "../common"
    }
  ]
}

for anyone still stuck on this:

node -r ts-node/register/transpile-only -r tsconfig-paths/register dist/index.js

this is what you need to do.

This was asked around in many places, and apparently Typescript can make path aliases for development, but not production (Don't quote me on that, have been working with it for barely a month).

To work around that, I installed 'module-alias', a package that solves the path issue after build, without interfering with development.

I was building an Express-js app, and had these files:

server.js:

import env from '@env';
import app from './app';

app.listen(env.SERVER_PORT || 3000);

tsconfig.json (relevant parts):

{
  "compilerOptions": {
    "baseUrl": "./src",
    "paths": {
      "@env": ["path/to/env"]
    }
  }
}

This resolved the path during development runtime, but not after building with 'tsc'. To work around it, I added the 'module-alias' package and did the following changes:

server.js:

import './paths';
import env from '@env';
import app from './app';

app.listen(env.SERVER_PORT || 3000);

paths.js

import 'module-alias/register';
import { addAliases } from 'module-alias';

addAliases({
  '@env': `${__dirname}/path/to/env`,
});

This ensured that @env would resolve in both dev runtime and after building. Hope it helps!

Also tried to build with tsc but failed due aliases. After reading a comment from the ts-node author, I skip the build phase and run in production

ts-node --transpileOnly -r tsconfig-paths/register src/server.ts

If you don't want to use ts-node in production environment, you can create a new js file to map your paths at runtime:

// tsconfig-paths.js

const tsConfig = require('./tsconfig.json');
const tsConfigPaths = require('tsconfig-paths');

let { baseUrl, paths } = tsConfig.compilerOptions;

// Replacing "src" by "dist" in typescript paths map
for (path in paths) {
  paths[path] = paths[path].map((path) => path.replace("src", "dist"));
}

tsConfigPaths.register({ baseUrl, paths });

And then add it to the node params:

// package.json
// ...
  "scripts": {
    "build": "tsc",
    "start": "node -r ./tsconfig-paths.js dist/main.js",
// ...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM