cevek / ttypescript

Over TypeScript tool to use custom transformers in the tsconfig.json
1.53k stars 56 forks source link

ttsc watch mode calls transformers many times per one compilation #106

Open timocov opened 3 years ago

timocov commented 3 years ago

I'm not sure whether it's TypeScript bug itself or even if intended behaviour.

  1. Unzip project.zip
  2. Enter the folder with unzipped project
  3. npm install
  4. Run ./node_modules/.bin/ttsc
  5. Run ./node_modules/.bin/ttsc --watch --preserveWatchOutput
  6. Compare output between them:

    $ ./node_modules/.bin/ttsc
    transformer factory
    transformer function for context
    transformer function for source file
    transformer function for context
    transformer function for source file
    transformer function for context
    transformer function for source file
    
    $ ./node_modules/.bin/ttsc --watch --preserveWatchOutput
    [10:40:00] Starting compilation in watch mode...
    
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer function for context
    transformer function for source file
    transformer factory
    transformer function for context
    transformer function for source file
    transformer factory
    transformer function for context
    transformer function for source file
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    transformer factory
    [10:40:02] Found 0 errors. Watching for file changes.

The main difference here is that transformer factory called multiple times in watch mode and it seems that for every file in watch mode it creates its own transformer function.

Transformer is pretty simple here and it is here just to show this "strange" behaviour:

import * as ts from 'typescript';
export default function (program: ts.Program) {
    console.log('transformer factory');

    return (ctx: ts.TransformationContext) => {
        console.log('transformer function for context');

        return (sourceFile: ts.SourceFile) => {
            console.log('transformer function for source file');

            function visitor(node: ts.Node): ts.Node {
                return ts.visitEachChild(node, visitor, ctx);
            }

            return ts.visitEachChild(sourceFile, visitor, ctx);
        };
    };
}

I think that in common case it doesn't lead any issue, but when a transformer tries to analyse the whole program (and probably generates some caches from program's state) it might produce strange bug that watch mode takes much more times rather than non-watch one, e.g. https://github.com/timocov/ts-transformer-properties-rename in https://github.com/tradingview/lightweight-charts increases compilation time in watch mode from several seconds to several minutes because of that.

If it's intended behaviour, what's the best way and approach to make the program analysing and generating program's caches? I thought transformer factory is that place...