Skip to content

Instantly share code, notes, and snippets.

@attentive
Last active February 6, 2024 14:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save attentive/de2e8b9d6a93a743d3ba517c4f7bfcdd to your computer and use it in GitHub Desktop.
Save attentive/de2e8b9d6a93a743d3ba517c4f7bfcdd to your computer and use it in GitHub Desktop.
Using tsconfig "paths" path aliases with Angular and tsc-alias

Getting tsconfig "paths" path aliases to work with Angular using tsc-alias

If you look around you'll find quite a few people complaining that Angular CLI doesn't work "out of the box" with path aliases for the TypeScript compiler.

Fortunately the handy tool tsc-alias will run the rule over your compiled output and replace the still-present path aliases from your dev codebase with correctly resolved relative paths.

This tool mostly works correctly out of the box, but there are a couple of frustrating gotchas:

  1. Angular sets up custom tsconfig.json files everywhere (eg tsconfig.lib.json). Tools such as ESLint etc don't love this practice and the TypeScript compiler itself doesn't recognise these files or apply their "paths" aliases correctly.
  2. Angular sets up an outDir property in the tsconfig.lib.json which it overrides via angular.json.
  3. This outDir has to be what tsc-alias needs to see in the modified package.json build script for the tool to work.

Good luck mates …

{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"cli": {
"schematicCollections": ["@angular-eslint/schematics"],
"analytics": false
},
"projects": {
"@my-namespace/my-project": {
"projectType": "library",
"schematics": {
"@schematics/angular:component": {
"standalone": true,
"style": "scss"
}
},
"root": "projects/my-namespace/my-project",
"sourceRoot": "projects/my-namespace/my-project/src",
"prefix": "my-namespace",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:ng-packagr",
"options": {
"project": "projects/my-namespace/my-project/ng-package.json"
},
"configurations": {
"production": {
"tsConfig": "projects/my-namespace/my-project/tsconfig.prod.json"
},
"development": {
// *This* is the name you'll have to change to `tsconfig.json` to get stuff to work ...
"tsConfig": "projects/my-namespace/my-project/tsconfig.json"
}
},
"defaultConfiguration": "production"
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
// This is where I ended up putting my original `tsconfig.spec.json` for this library
"tsConfig": "projects/my-namespace/spatial/src/test/tsconfig.json",
"polyfills": ["zone.js", "zone.js/testing"],
"karmaConfig": "projects/my-namespace/spatial/karma.conf.js",
"sourceMap": true
}
},
// … more …
}
}
}
}
// Read the comments to understand various arcana
{
"name": "my-namespace",
"version": "0.0.1",
"scripts": {
"ng": "ng",
// add an extra command to your usual 'ng build' script (run all this with `npm run build:my-project`)
"build:my-project": "ng build --project @my-namespace/my-project && tsc-alias -p projects/my-namespace/my-project/tsconfig.json"
// … others …
},
"dependencies": {
"@angular/core": "^16.1.3",
// … and lots of others …
},
"devDependencies": {
"@angular-devkit/build-angular": "^16.1.3",
"@angular/cli": "^16.1.3",
"@angular/compiler-cli": "^16.1.3",
"tsc-alias": "^1.8.8",
"typescript": "~4.9.4",
// … and lots of others but obviously tsc-alias (via `npm install --save-dev tsc-alias`) is the key here
}
}
// Read the comments to understand various arcana
// This filename *must* be `tsconfig.json` and not `tsconfig.lib.json` otherwise tsc won't recognise your "paths"
// This means variants such as `tsconfig.spec.json` can't live side by side and have to be rebased, but that's easy
// The file you'll find at `projects/my-namespace/my-project in your Angular ng-packagr monorepo.
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
// baseUrl: required for anything to work
"baseUrl": "./",
"paths": {
// an example path alias - will let you do eg import { MyComponent } from '@components/my-component/my-component'
// (which is the whole point of this)
"@components/*": ["src/lib/components/*"],
},
"allowSyntheticDefaultImports": true,
"experimentalDecorators": true,
// this *must* be set to the actual output directory specified in your angular.json in the build section for this project
// (Angular defaults it to something else then overrides it, but tsc-alias uses this value)
"outDir": "../../../dist/my-namespace/my-project",
"declaration": true,
"declarationMap": true,
"inlineSources": true
},
"tsc-alias": {
"resolveFullPaths": true
// optionally make tsc-alias log more
// "verbose": true,
// optionally do many other things (eg add extra replacers, change the file extensions being processed etc)
// default inputGlob includes something like "{mjs,cjs,js,jsx,d.{mts,cts,ts,tsx}}"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment