tsc-alias

repository·master·Indexed 22 days ago

https://github.com/justkey007/tsc-alias

A tool and API for replacing TypeScript alias paths with relative paths in compiled output, allowing code to run without runtime path resolution like tsconfig-paths. It provides a CLI, a programmatic API via replaceTscAliasPaths, and a single-file replacement utility via prepareSingleFileReplaceTscAliasPaths. Supports configuration through tsconfig.json, custom replacers, and watch mode.

Tokens
4.2K
Snippets
14
Records
16
Agent score
78%

What's inside tsc-alias

  1. Install tsc-alias

    master

    You can install tsc-alias either globally or as a development dependency in your project.

    To install globally:

    npm install -g tsc-alias

    To install as a devDependency (recommended):

    npm install --save-dev tsc-alias
    npm install --save-dev tsc-alias
  2. Use tsc-alias in build scripts

    master

    To use tsc-alias in your workflow, add it to your package.json scripts after the TypeScript compilation step (tsc). This ensures that alias paths are replaced with relative paths in the compiled output.

    Standard build script:

    "scripts": {
      "build": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json"
    }

    Watch mode (using concurrently): If you want to watch for changes in both TypeScript and your aliases, you can use concurrently:

    "scripts": {
      "build:watch": "tsc && (concurrently \"tsc -w\" \"tsc-alias -w\")"
    }
    "scripts": {
      "build": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
    }
  3. Configure tsc-alias via tsconfig.json

    master

    You can provide configuration for tsc-alias directly within your tsconfig.json file using a tsc-alias key. This is useful for setting up advanced options like custom replacers or file extension patterns.

    {
      "compilerOptions": {
        ...
      },
      "tsc-alias": {
        "verbose": false,
        "resolveFullPaths": true,
        "replacers": {
          "exampleReplacer": {
            "enabled": true,
            "file": "./exampleReplacer.js"
          },
          "otherReplacer": {
            "enabled": true,
            "file": "./otherReplacer.js"
          }
        },
        "fileExtensions": {
          "inputGlob": "{js,jsx,mjs}",
          "outputCheck": ["js", "json", "jsx", "mjs"]
        }
      }
    }
  4. Avoid name collisions between source files and npm packages

    master

    A regression in tsc-alias version 1.9.0 causes issues when a source file has the same name as an npm package it imports. If you have a file named src/redis.ts and you import from the redis npm package, tsc-alias 1.9.0 may incorrectly rewrite the import to a relative path pointing to the file itself (require("./redis")) instead of the npm package. This causes the module to require itself, leading to runtime errors like TypeError: (0 , redis_1.createClient) is not a function because the named export becomes undefined.

    // src/redis.ts
    import { createClient } from 'redis'; // This may be incorrectly rewritten to './redis'
    const client = createClient();
  5. Reproduce the tsc-alias 1.9.0 regression

    master

    To reproduce the bug where bare module specifiers are incorrectly rewritten to relative paths, use the following steps in an environment with tsc-alias 1.9.0 and TypeScript 6.0+ where tsconfig.json defines paths but lacks a baseUrl:

    1. Install dependencies: npm install
    2. Build the project: npm run build (which executes tsc --noCheck && tsc-alias)
    3. Check the compiled output: grep require dist/redis.js
    4. Run the output: node ./dist/redis.js
    npm install
    npm run build          # tsc --noCheck && tsc-alias
    grep require dist/redis.js
    # Expected error output: const redis_1 = require("./redis");
    
    node ./dist/redis.js
    # Expected error: TypeError: (0 , redis_1.createClient) is not a function
  6. Use the Single File Replacer API

    master

    If you need to process a single file manually rather than a whole project, use prepareSingleFileReplaceTscAliasPaths. This returns a function that can be used to transform file contents synchronously.

    1. Call prepareSingleFileReplaceTscAliasPaths(options?) to get a SingleFileReplacer function (returns a Promise).
    2. Pass an object containing { fileContents, filePath } to the resulting function.
    3. The function returns the transformed contents.
    import { prepareSingleFileReplaceTscAliasPaths } from 'tsc-alias';
    
    // 1. Prepare the replacer
    const runFile = await prepareSingleFileReplaceTscAliasPaths(options?);
    
    // 2. Use it on a specific file
    function treatFile(filePath: string) {
      const fileContents = fs.readFileSync(filePath, 'utf8');
      const newContents = runFile({ fileContents, filePath });
      // do stuff with newContents
    }
    import { prepareSingleFileReplaceTscAliasPaths } from 'tsc-alias';
    
    const runFile: SingleFileReplacer = await prepareSingleFileReplaceTscAliasPaths(options?);
    
    function treatFile(filePath: string) {
      const fileContents = fs.readFileSync(filePath, 'utf8');
      const newContents = runFile({fileContents, filePath});
      // do stuff with newContents
    }
  7. Use the replaceTscAliasPaths API

    master

    You can programmatically replace alias paths using the replaceTscAliasPaths function. This function accepts an optional configuration object.

    import { replaceTscAliasPaths } from 'tsc-alias';
    
    replaceTscAliasPaths(options?);
  8. Configure replaceTscAliasPaths options

    master

    The following options can be passed to replaceTscAliasPaths(options?):

    OptionDescriptionDefault
    project, pPath to tsconfig.json'tsconfig.json'
    watchObserve file changesfalse
    outDirRun in a folder leaving the "outDir" of the tsconfig.json (relative path to tsconfig)tsconfig.compilerOptions.outDir
    declarationDirWorks the same as outDir but for declarationDirtsconfig.compilerOptions.declarationDir
    resolveFullPathsAttempt to replace incomplete import paths (those not ending in .js) with fully resolved paths (for ECMAScript Modules compatibility)false
    resolveFullExtensionAllows you to specify the extension of incomplete import paths, works with resolveFullPaths'.js' | '.mjs' | '.cjs'
    silentReduced terminal output. (Deprecated, no longer has effect)true
    verboseAdditional information is output to the terminalfalse
    debugDebug information is sent to the terminalfalse
    replacersFiles to import as extra replacers[]
    outputThe output object tsc-alias will send logs tonew Output(options.verbose)
    fileExtensionsOverwrite file extensions tsc-alias will use to scan and resolve filesundefined
  9. Replace aliases in a single file with prepareSingleFileReplaceTscAliasPaths()

    master

    If you need to perform alias replacement on specific file contents manually (for example, within a custom build pipeline or a virtual file system), use prepareSingleFileReplaceTscAliasPaths.

    This function returns a SingleFileReplacer function. You call this returned function with an object containing the fileContents and the filePath to get the transformed string back.

    Usage Pattern:

    1. Call prepareSingleFileReplaceTscAliasPaths(options) to get the replacer function.
    2. Invoke the replacer with { fileContents, filePath }.
    import { prepareSingleFileReplaceTscAliasPaths } from 'tsc-alias';
    
    const replacer = await prepareSingleFileReplaceTscAliasPaths({
      // your options here
    });
    
    const transformedContent = replacer({
      fileContents: 'import { something } from "@alias/module";',
      filePath: '/path/to/file.ts'
    });
    // transformedContent will have the alias replaced
  10. Configure ReplaceTscAliasPathsOptions

    master

    When using the tsc-alias API, you can pass an options object implementing ReplaceTscAliasPathsOptions to control the path replacement process. Key configuration options include:

    • configFile: Path to your tsconfig.json.
    • outDir: The directory where compiled files are located.
    • declarationDir: The directory where .d.ts files are located.
    • watch: Boolean to enable watch mode.
    • verbose: Enables verbose logging.
    • debug: Enables debug logging.
    • resolveFullPaths: Boolean to resolve full paths.
    • resolveFullExtension: Specifies the extension to resolve to: '.js', '.mjs', or '.cjs'.
    • replacers: An array of strings (likely identifiers or patterns for custom replacers).
    • output: An object implementing IOutput for custom logging.
    • aliasTrie: A pre-computed TrieNode<Alias> for path matching.
    • fileExtensions: Configuration for input/output file matching via Partial<FileExtensions>.
    export interface ReplaceTscAliasPathsOptions {
      configFile?: string;
      outDir?: string;
      declarationDir?: string;
      watch?: boolean;
      verbose?: boolean;
      debug?: boolean;
      resolveFullPaths?: boolean;
      resolveFullExtension?: '.js' | '.mjs' | '.cjs';
      replacers?: string[];
      output?: IOutput;
      aliasTrie?: TrieNode<Alias>;
      fileExtensions?: Partial<FileExtensions>;
    }
  11. Implement a custom IOutput logger

    master

    If you are calling the API programmatically, you can provide a custom IOutput object to control how tsc-alias logs information to the console. This is useful for integrating tsc-alias into custom build pipelines or CLI tools.

    The IOutput interface requires the following methods:

    • debug(message: string, obj?: unknown): Logs at debug level.
    • info(message: string): Logs at info level.
    • error(message: string, exitProcess?: boolean): Logs an error; exitProcess determines if the process should terminate.
    • clear(): Clears the displayed logs.
    • assert(claim: unknown, message: string): Asserts a condition; logs an error and exits if the claim is falsy.
    export interface IOutput {
      verbose: boolean;
      debug: (message: string, obj?: unknown) => void;
      info(message: string): void;
      error(message: string, exitProcess?: boolean): void;
      clear(): void;
      assert(claim: unknown, message: string): void;
    }
  12. Customize path replacement with AliasReplacer

    master

    You can intercept and modify how import statements are rewritten by providing custom replacers. An AliasReplacer is a function that receives AliasReplacerArguments and returns the new import string.

    AliasReplacerArguments contains:

    • orig: The original import statement string.
    • file: The path of the file being processed.
    • config: The current IConfig object.

    Additionally, you can use ReplacerOptions to enable or disable specific replacers, optionally scoped to a specific file.

    export type AliasReplacer = (args: AliasReplacerArguments) => string;
    
    export interface AliasReplacerArguments {
      orig: string;
      file: string;
      config: IConfig;
    }
    
    export interface ReplacerOptions {
      [key: string]: {
        enabled: boolean;
        file?: string;
      };
    }