Reputation: 1163
I'm running VS Code and I am currently trying to set up some aliases on my typescript project.
My dev setup rest on nodemon and ts-node, the code gets compiled to a dist folder.
So far, I succeeded to get Typescript Hero to manage the import with aliases:
So far, my folder structure is:
.
└─┬ src
├──modules
├────Category
├────Ressource
├──shared
├────debug
// tsconfig.json
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"pretty": true,
"sourceMap": true,
"target": "es6",
"outDir": "./dist",
"baseUrl": "./src",
"paths": {
"@shared/*": [
"shared/*"
],
"@modules/*": [
"modules/*"
]
},
"resolveJsonModule": true,
"esModuleInterop": true
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"**/*.spec.ts",
"**/*.test.ts",
]
}
And this is the first alias import that fails.
//Server.ts file
import Print from '@shared/debug/Print.class';
import App from './App';
const MyApp: App = new App();
MyApp.ExpressApp.listen(MyApp.Config.ExpressPort, () => {
Print.Log('Express server listening on port ' + MyApp.Config.ExpressPort);
});
However, I get an error: "Cannot find module '@shared/debug/Print.class'" on "cross-env NODE_ENV=development nodemon ts-node ./src/server.ts".
And this is where I stand.
Now, I've read some Q&A on SO, and it seems that even if I managed to make the aliases works while in dev, it would fail in production, as I'm running from Typescript src folder and my deliverable are built in dist ? If so, is there any way to remediate ? Many thanks
Upvotes: 37
Views: 50429
Reputation: 1
There is a package called tsc-alias include it along side scripts in package.json npx tsc && tsc-alias this would resolve the paths so that we can run it with node. I believe this is much easier and cleaner
"scripts": {
"build": "npx tsc && tsc-alias"
}
Upvotes: 0
Reputation: 1362
You're using ts-node
and nodemon
to run your code, so you should add this to your tsconfig.json
file:
{
"ts-node": {
"require": ["tsconfig-paths/register"]
}
}
And then install tsconfig-paths/register
as a dev dependency.
npm install --save-dev tsconfig-paths
UPDATE: If you're looking for a solution that requires no configuration, consider using tsx
as an alternative to ts-node
and nodemon
in your project.
Here’s what you can do:
ts-node
with tsx
.tsx --watch
instead of nodemon
.Upvotes: 20
Reputation: 1448
Let's simplify it:
tsc-alias
will fix tsc
tsconfig-paths/register
will deal with ts-node
and nodemon
.The usage, as the others said, is simple. First, install it:
npm i -D tsc-alias tsconfig-paths
Then you can update your scripts to use them
{
"scripts": {
"start": "node dist/app.js",
"dev": "ts-node -r tsconfig-paths/register src/app.ts",
"build": "tsc && tsc-alias",
"watch": "nodemon --watch ./src --exec 'ts-node -r tsconfig-paths/register src/app.ts'"
}
}
Other options are:
tsx
: replaces tsc
.ts-node-dev
: replaces nodemon
--watch
flag: node v18.11 and aboveUpvotes: 2
Reputation: 491
I faced the same problem and CrazyYoshi solution is not worked properly in my case.
I fixed it with putting this code in tsconfig.json
:
{
"ts-node": {
// Do not forget to `npm i -D tsconfig-paths`
"require": ["tsconfig-paths/register"]
}
}
After it do not forget to install tsconfig-paths
module:
npm i -D tsconfig-paths
Documentation: https://typestrong.org/ts-node/docs/paths/
Upvotes: 36
Reputation: 387
I installed tsc-alias
in my express js project to handle aliases paths with nodemon
:
and it works for me correctly :).
tsconfig.json
file:
{
"compilerOptions": {
...,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}
and this is my nodemon.json
file :
{
"watch": ["src"],
"ext": "ts",
"exec": "concurrently \"npx tsc && tsc-alias && ts-node dist/main.js\""
}
and this is my package.json
:
{
"name": "rest-mongoose",
"version": "1.0.0",
"description": "",
"main": "./dist/main.ts",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "npx tsc && tsc-alias",
"start": "npm run build && node dist/main.js",
"dev": "nodemon"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.3.2",
"express": "^4.18.2",
"mongodb": "^6.3.0",
"mongoose": "^8.1.0"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20.11.5",
"concurrently": "^8.2.2",
"nodemon": "^3.0.3",
"ts-node": "^10.9.2",
"tsc-alias": "^1.8.8",
"typescript": "^5.3.3"
}
}
You can run your project on development mode with bottom command:
npm run dev
Upvotes: 0
Reputation: 569
Easy: Just use tsx, works perfectly and requires zero setup.
npx tsx ./path-to-your-script
Upvotes: -1
Reputation: 385
March 2023
Just spent literally hours trying to get this to work. In the end, I ended up ditching ts-node entirely and installing tsx which just worked straight out of the box.
Apparently, this is coming to ts-node eventually, although the PR kind of looks dead so who knows:
https://github.com/TypeStrong/ts-node/pull/1585
In the mean time, if you really want to stick with ts-node you may find the following useful:
https://www.npmjs.com/package/@bleed-believer/path-alias
https://github.com/TypeStrong/ts-node/issues/1007
https://github.com/TypeStrong/ts-node/discussions/1450#discussioncomment-1806115
Upvotes: 14
Reputation: 61
I think you can use the package called module-alias
to solve this problem.
First, install it with yarn, npm or pnpm, choose one what you use.
Then, add same alias to your package.json
just like:
{
"_moduleAliases": {
"@shared": "./src/shared",
"@modules": "./src/modules"
}
}
Finally, to import module-alias/register
in your first line(that's important)!
import 'module-alias/register'
// ... your other code
This is the address of module-alias
You can refer to it.
I hope my answer will help you to solve it.
Upvotes: 6
Reputation: 1163
The problem was situated on node path aliases resolution on runtime. Even if the typescript was executed on runtime by ts-node, the aliases couldn't be resolved by node as-is. (I think)
But this was only the tip of the iceberg. I'd encounter it then later with my jest setup, and on JS runtime.
I had to find a way, for every runtime I had, to interpret my aliases. There was a few npm packages but a lot of them required more declarations.
And I didn't want to declare my aliases in every config files I'd have and only depend on my tsconfig file.
After much testings, there was only two node modules to install tsconfig-paths for typescript runtime execution on ts-node. And @ef-carbon/tspm to convert my aliases to the build destination.
npm i -D tsconfig-paths @ef-carbon/tspm
For ts-node, the script was modified as :
ts-node -r tsconfig-paths/register ./src/server.ts
For your js compiled, you only have to run :
ef-tspm
For jest, ts-jest is needed, I already had it but it wasn't properly configured. I used the built-in helper to set up my paths. My jest config file now looks like this :
//jest.config.js
const { pathsToModuleNameMapper } = require('ts-jest/utils');
const { compilerOptions } = require('./tsconfig');
module.exports = {
roots: ['<rootDir>/src'],
globals: {
'ts-jest': {
tsConfig: 'tsconfig.json',
diagnostics: {
warnOnly: true,
},
},
},
clearMocks: true,
coverageDirectory: 'coverage',
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$',
moduleFileExtensions: ['js', 'json', 'jsx', 'node', 'ts', 'tsx'],
testEnvironment: 'node',
moduleNameMapper: pathsToModuleNameMapper(compilerOptions.paths, { prefix: '<rootDir>/src/' }),
pathToJest: 'npm test',
preset: 'ts-jest',
testMatch: null,
};
Here is, how my scripts look like in my package.json
"scripts": {
"dev:ts": "cross-env NODE_ENV=development nodemon",
"dev:js": "cross-env NODE_ENV=development npm run start:js",
"staging": "cross-env NODE_ENV=staging npm run start:js",
"production": "cross-env NODE_ENV=production npm run start:js",
"test": "cross-env NODE_ENV=testing jest --runInBand",
"test:debug": "npm run test --detectOpenHandles",
"start:js": "npm run build && nodemon --config nodemon-js.json",
"build": "npm run compile && npm run post:compile && npm run copyAssets",
"compile": "tsc",
"post:compile": "ef-tspm",
"copyAssets": "copyfiles -e ./src/**/*.ts -e ./src/**/*sample* -e ./src/**/*.json -u 1 ./src/**/* ./dist/"
},
Seeing how it goes, I'll probably add a grunt/gulp solution afterward. But for now, this is good enough.
Upvotes: 54