Error in buildTypeScript: A project cannot be used in two compilations at the same time
See original GitHub issueI’m submitting a bug report
- Library Version: 0.18.0 (CLI)
Please tell us about your environment:
- Operating System: OSX 10.11.6
- Node Version: 6.1.0
- NPM Version: 3.8.6
- Browser: all
- Language: TypeScript 1.8.10
Current behavior:
Frequently, when running au run --watch
the TypeScript compile seems to hang.
In the Activity Monitor I can see that the aurelia process suddenly keeps using lots of CPU:
Also, the Terminal window seems to hang. Meaning I’m unable to kill the process with Ctrl+C, where it leads to a long stacktrace like:
File Changed: src/views/devices/device-overview.ts
Starting 'readProjectConfiguration'...
Starting 'readProjectConfiguration'...
Finished 'readProjectConfiguration'
Finished 'readProjectConfiguration'
Starting 'processMarkup'...
Starting 'processCSS'...
Starting 'processMarkup'...
Starting 'processCSS'...
Starting 'configureEnvironment'...
Starting 'configureEnvironment'...
Finished 'configureEnvironment'
Starting 'buildTypeScript'...
Finished 'configureEnvironment'
Starting 'buildTypeScript'...
{ uid: 292,
name: 'buildTypeScript',
branch: false,
error:
{ Error: gulp-typescript: A project cannot be used in two compilations at the same time. Create multiple projects with createProject instead.
at compile (/Users/Hanssens/Work/git/xxx/app/node_modules/gulp-typescript/release/main.js:72:19)
at buildTypeScript (/Users/Hanssens/Work/git/xxx/app/aurelia_project/tasks/transpile.ts:32:15)
at bound (domain.js:280:14)
at runBound (domain.js:293:12)
at asyncRunner (/Users/Hanssens/Work/git/xxx/app/node_modules/async-done/index.js:36:18)
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickDomainCallback (internal/process/next_tick.js:122:9)
domain:
Domain {
domain: null,
_events: {},
_eventsCount: 0,
_maxListeners: undefined,
members: [] },
domainThrown: true },
duration: [ 0, 1050860 ],
time: 1472216741812 }
In order to resolve this, I need to manually force quit the aurelia process in the Activity Monitor.
Expected/desired behavior: Expected behaviour is that it would not crash. Steps that can reproduce it:
- Start Visual Studio Code
- Add several .ts files
- Frequently edit and save the .ts files at random
In two projects I can reproduce this about every 10~15 minutes or so. Depending on how many changes I make, of course.
- What is the expected behavior? Expected behaviour is NOT a crash.
- What is the motivation / use case for changing the behavior? Fixing the crash.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:3
- Comments:34 (14 by maintainers)
Top Results From Across the Web
asp.net mvc - How can I build TypeScript as a project separate ...
Update the TypeScript or encounter a compilation error at next build time. I don't like this because I can't automatically run TypeLite as...
Read more >TypeScript Compiling with Visual Studio Code
TypeScript is a typed superset of JavaScript that transpiles to plain JavaScript. It offers classes, modules, and interfaces to help you build robust...
Read more >Compile and build TypeScript code using NuGet
Learn how to add TypeScript support to your Visual Studio projects by using the NuGet package.
Read more >Documentation - Gulp - TypeScript
Then install typescript , gulp and gulp-typescript in your project's dev ... Even better, it lets us use the CommonJS module system used...
Read more >How to Setup a TypeScript project using Rollup.js
A couple of months ago, I started to work through web standards, Rollup.js, and TypeScript. It's my first experience using Rollup although ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
@EisenbergEffect I decided to take that challenge 😃, and spent some more hours today looking into this. I think I found a very promising, comprehensive solution to the problem that not only gets rid of the crashes, but also introduces some tremendous performance improvements for the watcher scenario. Let me give you an idea of what I’m talking about:
Basically, I applied three or four changes, depending on how you look at it.
Important: When I sat down to work on this, I decided to do my experiments on the build task (build.ts), not to the run task (run.ts). This feature (“build --watch”) also has been requested before (see: https://github.com/aurelia/cli/issues/265), and since we are not using the built-in serve feature at all, it was the logical thing to do for me. The following concepts however fully apply in the same way, no matter where you put the watcher logic, and simply would require to pass some of the information described below from the run task to the build task if you prefer to put it in the run task. I would of course appreciate if that “build --watch” I just created also found it’s way into the official code base 😃.
1. Change the way you use gulp.watch
If you would only want to fix the crashes and keep the incremental build features of TypeScript, you would need to do the following:
What I would recommend in addition however, is to switch from the built-in gulp.watch feature to the separate gulp-watch package (subtle difference but huge improvement). The built-in feature does not pass on information about individual file changes, which makes further optimization difficult. The changes described in the details that follow rely on this, so if you want to add that benefit, you need to switch to gulp-watch (or a similar package that supports this).
Another small optimization is to turn off content reading. By default, the watcher reads the file contents, but they are thrown away because the actual build process re-reads them using gulp.src. For gulp-watch, there’s official documentation about how to turn content reading off (see options.read). Since both the built-in gulp.watch feature and gulp-watch rely on chokidar, I would suspect that should also work for gulp.watch (although it’s not documented there and I didn’t test that). Sample:
2. Debounce
The above solution fixes the crashes and improves performance for simple scenarios, but still has the “multiple successive builds” problem when more than one file is changed rapidly (“save all”). So I decided to take a look at debouncing the build. Amazingly, this took the most time to get right. The problem mostly is with finding a solution that integrates nicely with the function composition in combination with the asynchronity of gulp. If you look around you’ll find quite some discussions around this and how it should be done (for example here: https://github.com/gulpjs/gulp/issues/1304). I use the default “debounce” Node package. If you choose a different package, make sure it does the triggering on the trailing edge or at least can be configured/forced to do so.
The proposed solution(s) all had the problem that they could not be applied easily to the Aurelia CLI, mostly because the underlying gulp wrapper of the CLI apparently makes some assumptions about the tasks structure and crashes if these are not satisfied (I mostly had problems with the
makeInjectable
function in Aurelia CLI’s gulp.js). Since I didn’t want to dig that deep into the code base, I preferred bridging to the gulp world of things with a simple manual solution. It basically looks like that (that’s pseudo-code, the full/real code follows below):There are probably nicer solutions than that, but like I said I wanted to fix this on the project template level and not dig into the Aurelia CLI package itself.
3. Selective builds
With that in place you get rid of the crashes and prevent rapid changes to multiple files triggering multiple successive builds. Basically, you’ll reach the “9 seconds” per incremental build performance level I mentioned in the beginning. Now, as you can see from these performance numbers above, our LESS task contributes the most to incremental build times, where at the same time we actually do not much of LESS editing in our day-to-day work. With that in mind I decided it would be nice to only trigger those parts of the build process which actually need to be performed, for example only do a TypeScript compile if we actually changed .ts files etc. To achieve this, here is what I did:
Ok, let’s put the puzzle pieces together and see what we get.
The refresh function itself is the one that’s debounced, and looks like that:
The remaining build.ts content stays more or less the same, I only added the --watch command line option. Like that:
I hope this is detailed enough so at least some of the improvements can find their way into your code base; providing a full working sample is not that easy as I would have to go over the code base and remove more company specific details, which I also stripped from the above fragments. I would love to see the CLI improve in that direction so others can benefit from these changes too.
Cheers 😃
@MisterGoodcat Thanks for taking a look! Glad it looks okay. I’m not surprised it performs like your implementation, though, because a lot of it pretty much is your implementation. 😃