Rollup-plugin-typescript2: Compilation very slow with TS v3.4

Created on 9 Apr 2019  ·  21Comments  ·  Source: ezolenko/rollup-plugin-typescript2

What happens and why it is wrong

Once I upgraded TS to v3.4.2, the compilation time is very slow. With TS v3.3 my project built in ~20s and with TS v3.4 it takes ~5mn.

I tried with clean: true, I tried to add typescript: require('typescript'), I tried to upgrade rollup and all the related plugins.. Each time, same result the compilation takes a lot of time.

Note: when I run tsc -p tsconfig.prod.json directly, it takes less than 10 seconds to output the dist.

Environment

Versions

  • typescript: v3.4.2
  • rollup: v1.6.0
  • rollup-plugin-typescript2: v0.19.2

rollup.config.js

  {
    input: 'src/index.ts',
    output: [
      { file: pkg.main, format: 'cjs' },
      { file: pkg.module, format: 'es' },
    ],
    plugins: [
      external({ includeDependencies: true }),
      resolve(),
      typescript({
        tsconfig: './tsconfig.prod.json',
        rollupCommonJSResolveHack: true,
      }),
      commonjs(),
      filesize(),
    ],
  }

tsconfig.json


tsconfig.json

{
  "compilerOptions": {
    "module": "esnext",
    "target": "es5",
    "jsx": "react",
    "esModuleInterop": true,
    "lib": ["dom", "es2017"],
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": false,
    "downlevelIteration": true
  },
  "include": ["src/**/*", "types/**/*"]
}


tsconfig.prod.json

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "noUnusedLocals": true,
    "sourceMap": true,
    "declaration": true
  },
  "exclude": ["src/doc", "**/stories.tsx", "**/test.tsx", "**/fixture.ts"]
}

package.json

    "rollup": "^1.6.0",
    "rollup-plugin-commonjs": "^9.2.1",
    "rollup-plugin-filesize": "^6.0.1",
    "rollup-plugin-node-resolve": "^4.0.1",
    "rollup-plugin-peer-deps-external": "^2.2.0",
    "rollup-plugin-typescript2": "^0.19.2",
    "typescript": "^3.4.2"

plugin output with verbosity 3


Output

rpt2: typescript version: 3.4.2
rpt2: tslib version: 1.9.3
rpt2: rollup-plugin-typescript2 version: 0.19.2
rpt2: plugin options:
{
    "tsconfig": "./tsconfig.prod.json",
    "rollupCommonJSResolveHack": true,
    "clean": true,
    "verbosity": 3,
    "typescript": "version 3.4.2",
    "check": true,
    "cacheRoot": "/Users/yannpringault/git/PayFit/components/.rpt2_cache",
    "include": [
        "*.ts+(|x)",
        "**/*.ts+(|x)"
    ],
    "exclude": [
        "*.d.ts",
        "**/*.d.ts"
    ],
    "abortOnError": true,
    "useTsconfigDeclarationDir": false,
    "tsconfigOverride": {},
    "transformers": [],
    "tsconfigDefaults": {},
    "objectHashIgnoreUnknownHack": false
}
rpt2: rollup config:
{
    "chunkGroupingSize": 5000,
    "experimentalCacheExpiry": 10,
    "inlineDynamicImports": false,
    "input": "src/index.ts",
    "perf": false,
    "plugins": [
        {
            "name": "peer-deps-external"
        },
        {
            "name": "node-resolve"
        },
        {
            "name": "rpt2"
        },
        {
            "name": "commonjs"
        },
        {
            "name": "filesize"
        }
    ]
}
rpt2: built-in options overrides: {
    "noEmitHelpers": false,
    "importHelpers": true,
    "noResolve": false,
    "noEmit": false,
    "inlineSourceMap": false,
    "outDir": "/Users/yannpringault/git/PayFit/components/.rpt2_cache/placeholder",
    "moduleResolution": 2,
    "allowNonTsExtensions": true,
    "declarationDir": "/Users/yannpringault/git/PayFit/components"
}
rpt2: parsed tsconfig: {
    "options": {
        "module": 6,
        "target": 1,
        "jsx": 2,
        "esModuleInterop": true,
        "lib": [
            "lib.dom.d.ts",
            "lib.es2017.d.ts"
        ],
        "moduleResolution": 2,
        "rootDir": "/Users/yannpringault/git/PayFit/components/src",
        "forceConsistentCasingInFileNames": true,
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "suppressImplicitAnyIndexErrors": true,
        "noUnusedLocals": true,
        "downlevelIteration": true,
        "outDir": "/Users/yannpringault/git/PayFit/components/.rpt2_cache/placeholder",
        "sourceMap": true,
        "declaration": true,
        "configFilePath": "/Users/yannpringault/git/PayFit/components/./tsconfig.prod.json",
        "noEmitHelpers": false,
        "importHelpers": true,
        "noResolve": false,
        "noEmit": false,
        "inlineSourceMap": false,
        "allowNonTsExtensions": true,
        "declarationDir": "/Users/yannpringault/git/PayFit/components"
    },
    "fileNames": [
        "/Users/yannpringault/git/PayFit/components/src/index.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/index.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/Alert/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Alert/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Avatar/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Avatar/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/AvatarGroup/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/AvatarGroup/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Badge/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Badge/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Button/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Button/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Checkbox/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Checkbox/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/CheckboxGroup/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/CheckboxGroup/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/DatePicker/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/DatePicker/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/DatePicker/Popin/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Dropdown/MenuContext.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/Dropdown/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Dropdown/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Dropdown/DropdownItem/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Dropdown/DropdownItem/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Field/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Field/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Icon/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Icon/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Input/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Input/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Layout/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Legend/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Legend/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Loader/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Loader/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/ProgressBar/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/ProgressBar/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/ProgressCircle/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/ProgressCircle/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/RadioGroup/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/RadioGroup/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Select/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Select/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Steps/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Steps/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Body.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Cell.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Footer.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Header.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/HeaderCell.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/HeaderRow.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Limit.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Table/components/Row.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/TableGroup/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/TableGroup/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Tag/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Tag/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Text/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Toggle/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Toggle/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Tooltip/index.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/Tooltip/style.tsx",
        "/Users/yannpringault/git/PayFit/components/src/components/_helpers/colors.test.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/_helpers/colors.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/_helpers/react.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/_helpers/string.test.ts",
        "/Users/yannpringault/git/PayFit/components/src/components/_helpers/string.ts",
        "/Users/yannpringault/git/PayFit/components/src/primitives/_helpers.tsx",
        "/Users/yannpringault/git/PayFit/components/src/primitives/box.tsx",
        "/Users/yannpringault/git/PayFit/components/src/primitives/text.tsx",
        "/Users/yannpringault/git/PayFit/components/src/utils/index.ts",
        "/Users/yannpringault/git/PayFit/components/src/utils/colors/index.ts",
        "/Users/yannpringault/git/PayFit/components/src/utils/shadows/index.ts",
        "/Users/yannpringault/git/PayFit/components/src/utils/shadows/test.ts",
        "/Users/yannpringault/git/PayFit/components/src/utils/zIndex/index.ts",
        "/Users/yannpringault/git/PayFit/components/types/index.d.ts",
        "/Users/yannpringault/git/PayFit/components/types/modules.d.ts"
    ],
    "typeAcquisition": {
        "enable": false,
        "include": [],
        "exclude": []
    },
    "raw": {
        "extends": "./tsconfig.json",
        "compilerOptions": {
            "outDir": "./dist",
            "noUnusedLocals": true,
            "sourceMap": true,
            "declaration": true
        },
        "exclude": [
            "src/doc",
            "**/stories.tsx",
            "**/test.tsx",
            "**/fixture.ts"
        ],
        "compileOnSave": false,
        "include": [
            "src/**/*",
            "types/**/*"
        ]
    },
    "errors": [],
    "wildcardDirectories": {
        "/users/yannpringault/git/payfit/components/src": 1,
        "/users/yannpringault/git/payfit/components/types": 1
    },
    "compileOnSave": false,
    "configFileSpecs": {
        "includeSpecs": [
            "src/**/*",
            "types/**/*"
        ],
        "excludeSpecs": [
            "src/doc",
            "**/stories.tsx",
            "**/test.tsx",
            "**/fixture.ts"
        ],
        "validatedIncludeSpecs": [
            "src/**/*",
            "types/**/*"
        ],
        "validatedExcludeSpecs": [
            "src/doc",
            "**/stories.tsx",
            "**/test.tsx",
            "**/fixture.ts"
        ],
        "wildcardDirectories": {
            "/users/yannpringault/git/payfit/components/src": 1,
            "/users/yannpringault/git/payfit/components/types": 1
        }
    }
}
rpt2: included:
'[
    "*.ts+(|x)",
    "**/*.ts+(|x)"
]'
rpt2: excluded:
'[
    "*.d.ts",
    "**/*.d.ts"
]'

blocked help wanted

Most helpful comment

@ezolenko Sorry for the late reply!

I put clean: true and upgraded rtp2 to 0.20.1. Here are the results:

TS 3.3.3333

build -> 18s
tsc   -> 14.39s

TS 3.3.4000

build -> 17.3s
tsc   -> 14.39s

TS 3.4.1

build -> 5m 25.1s
tsc   -> 21.26s

TS 3.4.3

build -> 5m 52.7s
tsc   -> 21.57s

Additionally there is this issue on the TS repo which seems related but I have @types/styled-components pinned to v4.1.4 so it doesn't cover my case.

Let me know if you need more infos.


For fun I also tried the latest 3.5 build:

TS 3.5.0-dev.20190413

build -> 1m 23.5s
tsc   -> 18.84s

All 21 comments

I'm having the same issue. Went from 24s to 345s when bumping TS from 3.3.4000 to 3.4.3

I tried to reproduce and at first I saw a slowdown, but using clean: true and going back and forth between typescript versions several times, I don't see the difference on clean build now...

Could you set clean: true, update rtp2 to latest (0.20.1 or master) and time a build several times in a row on ts 3.3 and ts 3.4?

@ezolenko Sorry for the late reply!

I put clean: true and upgraded rtp2 to 0.20.1. Here are the results:

TS 3.3.3333

build -> 18s
tsc   -> 14.39s

TS 3.3.4000

build -> 17.3s
tsc   -> 14.39s

TS 3.4.1

build -> 5m 25.1s
tsc   -> 21.26s

TS 3.4.3

build -> 5m 52.7s
tsc   -> 21.57s

Additionally there is this issue on the TS repo which seems related but I have @types/styled-components pinned to v4.1.4 so it doesn't cover my case.

Let me know if you need more infos.


For fun I also tried the latest 3.5 build:

TS 3.5.0-dev.20190413

build -> 1m 23.5s
tsc   -> 18.84s

That issue you found (https://github.com/Microsoft/TypeScript/issues/30663) and the fact that 3.5-dev became 5 times faster for you makes me think they did something with LanguageServer API. This is the API rpt2 uses as part of compilation and what typecheckers in IDEs are using (that's why WebStorm times out etc).

Your project might be using affected type structures elsewhere, that's why pinning styled-components doesn't help. And that's why I don't see a big slowdown when building rpt2 itself for example.

I guess we'll wait for final 3.5 release.

btw, try building with check: false option

Has anyone confirmed if this is this fixed with 3.5 release?

@tomasro27 Not for me, nor with 6 (3.6.0-dev.20190621). Seems < 3.3 is still the fastest.

It looks like 3.5 is a little bit faster but it could still be better

Is there any update on this? Seem like its still blocked by TS?

Yeah, I don't think anything can be done from this end. Anybody is welcome to try though :)

+1
3.5.3 is also very slow for us

check: false is working great.

But the problem is that it doesn't give any compilation error (if you use vscode, it'll prompt the errors 😄).

At least I can do check: false when I'm working on CSS (in JS). 👍

@ezolenko do you know what exact typescript api call causes the build to slow down? :)

@ZainlessBrombie no, everything I know is in this thread. Typescript issue that is linked is probably related, but not direct cause (because they say it should be fixed in 3.5+, and apparently it isn't).

If you have slow builds in your project, check if ts 3.3 is actually faster if possible, maybe the problem is not typescript, but something else.

Alright thanks. If I get around to it this might be a wall I'm willing to bash my head against so to speak :)

Edit: This problem only occurs for files that import styled components as it seems
Also, Typescript documentation is terrible

Profiling typescript reveals the source of the problem to be these extremely large unions that styled components has. The only place to fix this is typescript, unless there is a way to get typescript to cache module resolution (which it should).

I'm actually not using module resolution cache in nodeModuleNameResolver call here: https://github.com/ezolenko/rollup-plugin-typescript2/blob/b7c7389dcdf168715669520128ca656d6e940111/src/index.ts#L148

Not sure if that makes ts use default one or not use one at all.

Yes I saw that TODO :)
Unfortunately debugging the module resolution cache when used shows that it caches rebass but not styled components for some reason. It passes an internal cache for those...

I am currently in the process of migrating my C# codebase of my library to TypeScript and I'm using Rollup for bundling. (I had a custom C# > Haxe > JavaScript toolchain before). Unfortunately I am suffering also quite a lot on the compilation speed of my new TypeScript codebase which makes development quite hard.

If possible I am happy to provide some profiling reports if it is possible to generate them.

Here some insights to my project:

Usually I'm using ttypescript to do to some AST transformation.
Lines of Code: ~50000

rollup -c rollup.config.ts: ~9-10sec
rollup -c rollup.config.ts -w (initial compile): ~9-10sec
rollup -c rollup.config.ts -w (adding 1 alert in 1 TS file): ~20sec
rollup -c rollup.config.ts -w (removing alert again): ~20sec

tsc --version: 3.8.3
tsc --project tsconfig.json: ~6-7sec
tsc --project tsconfig.json -w (initial compile): ~6-7sec
tsc --project tsconfig.json -w (adding 1 alert in 1 TS file): ~0.1-0.2sec
tsc --project tsconfig.json -w (removing alert again): ~0.1-0.2sec

ttsc --version: 3.8.3
ttsc --project tsconfig.json: ~7-8sec
ttsc --project tsconfig.json -w (initial compile): ~6-7sec
ttsc --project tsconfig.json -w (adding 1 alert in 1 TS file): ~0.1-0.2sec
ttsc --project tsconfig.json -w (removing alert again): ~0.1-0.2sec

Incremental builds are active in the tsconfig.

It seems to me quite unusual that an incremental/watch build would take twice as much than a full build.

Things seem to go crazy in my environment when ti comes to testing. I hooked up rollup with karma and this typescript plugin. As you might know: each test suite gets its own bundle, which means the numbers of above pile up. Memory grows to >2GB over time; even after minutes the test run does not actually start. This happens on each single npm run test.

Once it reaches the "Generating bundle for..." area on the test generation I see ridiculous high numbers:
File01.test.ts containing 1 simple test of a parser class takes 15secs
File02.test.ts containing 11 XML parsing tests needs 2.5minutes
File03.test.ts did not even complete after 5 minutes.

I have no clue where this issue might be caused and if it is really due to the typescript module of rollup but this seemed to be the most likely issue I'm related to.

As my repo is quite large and complicated I did not share more details on configs. If anybody can guide me how to collect them, I'm happy to provide logs/profiling results etc. I will try to setup a new simple independent repository reflecting my overall project situation, but I cannot promise that the issue will persist.

@Danielku15 Your main problem is that you are migrating from C# and not from C++ :)

This plugin is not explicitly using typescript's own incremental builds (this didn't exist when it started).

You could try @rollup/plugin-typescript (https://github.com/rollup/plugins/tree/master/packages/typescript), they use a different approach I think and might give you different numbers.

Another option is to do typescript compilation out of rollup chain (as a prebuild step in npm or something) and feed resulting js to rollup instead. Watch build would be interesting, although I think you can start tsc and rollup in watch mode and if project is configured correctly it will just work.

Your main problem is that you are migrating from C# and not from C++

Off-Topic: I am not sure if I would like to migrate a C++ framework/library to TypeScript. Depending on the use of macros and templates (which C++ devs tend to love) things might go wild during migration 😅 Luckily my C# codebase was always tailored to a style that allows cross compilation to other languages so the result is quite acceptable from a code structure. I just need to figure out a bit better how to organize the modules to reduce some overhead. 😊

This plugin is not explicitly using typescript's own incremental builds (this didn't exist when it started).

This is interesting, is this plugin having some own custom "incremental" build strategy? This could explain why a full-clean build might be taking longer than an source change when using watch. The typescript compilation is more or less stable, it is unfortunate that this plugin cannot utilize the incremental updates yet, but I think the time spent in the type script compiler is stable. But the time spend in rollup seems to be varying. Only this explains to me that a clean build is faster than a code change with watch-mode.

You could try @rollup/plugin-typescript ...

Thanks for the hint I will give it a try to see if it improves.

Another option is to do typescript compilation out of rollup chain

I had such a setup at the very beginning but dropped it half way to have "watch" builds during development. I will give it again a shot if I can hook up a pipeline with the two tools "watching" independently. 👍

Update 1: I was able to setup my whole compile and test environment now with invoking tsc chained with rollup. I needed to make my own rollup plugin to resolve the tsconfig paths correctly but after that it was working fine.

Clean compilation: 9secs, Watch compilation: 0.5-1secs and tests via Karma + Rollup are also running (compilation there takes a bit longer as it generates a bundle for each test suite).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alireza-salemian picture alireza-salemian  ·  4Comments

vwxyutarooo picture vwxyutarooo  ·  15Comments

alshdavid picture alshdavid  ·  16Comments

eddow picture eddow  ·  14Comments

lijialiang picture lijialiang  ·  4Comments