rollup-plugin-typescript2: Compilation very slow with TS v3.4
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"
]'
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 32
- Comments: 28 (7 by maintainers)
For anyone else coming to this issue after finding rollup builds were intolerably (25 minutes for a large project) our solution after some investigation was rather simple. Setting
declaration: false
intsconfig.json
resulted in builds going down to under a minute. We now generate typings separately usingtsc
which only takes about 10s.@ezolenko Sorry for the late reply!
I put
clean: true
and upgraded rtp2 to0.20.1
. Here are the results:TS 3.3.3333
TS 3.3.4000
TS 3.4.1
TS 3.4.3
Additionally there is this issue on the TS repo which seems related but I have
@types/styled-components
pinned tov4.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
It’s important to note that even though esbuild is dope you will sacrifice some rather essential TypeScript features. Like for one, const enums are not supported plus a couple of other caveats. Another rather important feature that is lacking if one would choose to adopt the esbuild plugin into their stack will be the inability to elegantly handle TypeScript
paths{}
(remap imports).As per issue 70, rollup-plugin-esbuild requires you lean on @rollup/plugin-alias for handling remaps which is far from ideal. This becomes rather problematic in large projects that take advantage of import remaps because @rollup/plugin-alias is slow, verbose and requires you to explicitly define the entries and thus those speed gains made with esbuild are quickly taken away.
If you decide to choose the official @rollup/typescript plugin then be rest assured at some point you will run into issues and find yourself trying to debug something that will be directly related to that plugin. Given the rather incorrigible nature some official rollup plugin maintainers happen to retain - when (and trust me, it is a matter of when) you find yourself scouring previous issues of the official plugins repository in an attempt to fix whatever the problem you’ve encountered might be or even if you wish to submit a PR it will be met with red-tape and fatigue. Essentially, the juice is really not worth the squeeze on that one imo.
There is also tszip maintained by ctjlewis which might be a solution for some as it is using a
tsc
torollup
compile approach and can be customized depending on your time and needs.The fact remains that ts2 is clearly the breadwinner in the nexus of Rollup and TS support. It is not the fastest solution but it is the most stable and well maintained (side note: thanks ezolenko). There are some things you can do to help negate that, like those mentioned in previous comments here and while I am not sure if applicable maybe
assumeChangesOnlyAffectDirectDependencies
option withintsconfig.json
could help?Wishing everyone good karma, heath and happiness!
The bitter truth now is that you should use esbuild plugin instead of this one. And if you want a type checking you just need to run
tsc -noEmit
directly as an additional step.btw, try building with
check: false
optionupstream issue
Hi folks, just doing some housekeeping in the issues. I’m going to close this one out as it’s gone quite stale (no comments in 9 months) and as far as I can tell, there really isn’t anything we can do on this front since the slowdown is within TypeScript itself and not this plugin. rpt2 also does not specify a specific version of TS and is compatible with many versions (we only specify a minimum TS version).
This issue with TS v3.4 was also reproduced by other tools in TS ecosystem, e.g. https://github.com/s-panferov/awesome-typescript-loader/issues/633 . So it’s not specific to this plugin either (or even Rollup) in that sense.
rpt2 internal nuances
I’ve made a handful of optimizations here and there since I joined on to help maintain rpt2, but most of those have been cache or watch mode related. The CPU-bound nature of compilation and type-checking still remains and those are primarily just calls to the TS Compiler API, so there isn’t much speed-up to be had there. The rpt2 codebase is relatively small too, with the source at a bit over ~1k LoC, so very generically speaking, there isn’t too much overhead in the codebase itself.
We use the
LanguageService
API that IDEs use, and if I had to guess, this is slower thantsc
because it’s a file-oriented API as opposed to a whole Program-oriented API.tsc
is also faster as a single tool that encompasses the whole build, whereas rpt2 is just a single plugin in a Rollup build (and multiple plugins may perform parsing, as well as Rollup itself).Rollup also processes the code graph on a file-by-file basis, so file-oriented APIs are somewhat necessary for us to use. If we offload type-checking to another thread, as #113 suggests, then it might be possible to operate a bit differently in that case. But that has its own caveats, as if we don’t error out on type-check errors, that can cause the output JS to be problematic and cause Rollup to error out confusingly instead of a nice type error. Plus, the history of Webpack threading has shown that moving type-checking into a separate thread is not always a performance improvement and can sometimes negatively impact performance instead (it also uses more memory, since Node
worker_threads
are quite primitive with sharing memory, so they’re almost like separate processes). This likely depends heavily on the size and structure of your project, as well as the complexity of your types. I’ll do a deep dive with Webpack plugin issue references in that issue later, but that’s the gist of it.tuning
Overall, I don’t think there’s anything we can do to address this issue specifically. There may be other optimizations to be had in other issues, but this one itself is generic, caused by upstream TS itself, and doesn’t really have a course of action we can take. That being said, please feel free to continue recommending specific optimizations and the performance characteristics of different configurations, as those can be helpful / useful, especially to other users!
Off the top of my head, a few configurations that can change performance characteristics are:
rpt2 options:
check: false
disables type-checkingclean: true
disables rpt2’s caching. this may slow down some projects and speed up others, it depends. I imagine turning caching off may speed up compilation of smaller projects, where the I/O of a filesystem cache may not be worthwhile, whereas the default caching is probably better for larger projects. This has not been thoroughly benchmarked though.exclude
can be used to optimize filtering of filestransformers
in that less transformations = better perfuseTsconfigDeclarationDir
may improve perf as it skips Rollup’s emit APIs and instead writes directly to the FS. It may also improve perf if you have multiple Rollup outputs.Rollup options:
sourcemap: false
disables source mapstsconfig
options:emitDeclarationOnly: true
is supported as of0.33.0
/ #366, if you want to use Babel,esbuild
,swc
etc as transpiler and rpt2 as type-checker + declaration emitter. As others have mentioned above, note the caveats of not being able to useconst enum
etc with this configurationdeclaration: false
+declarationMap: false
disables declarations and declaration mapsYes 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…
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).
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
Yeah, I don’t think anything can be done from this end. Anybody is welcome to try though 😃
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
LanguageService
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.