Skip to content

Instantly share code, notes, and snippets.

@smac89
Last active July 6, 2017 21:13
Show Gist options
  • Save smac89/49f3b076cd987e0875ba9bfb3fe81ef9 to your computer and use it in GitHub Desktop.
Save smac89/49f3b076cd987e0875ba9bfb3fe81ef9 to your computer and use it in GitHub Desktop.
Solution to "Error: gulp-typescript: A project cannot be used in two compilations * at the same time. Create multiple projects with createProject instead."
import {Project, CompileStream} from 'gulp-typescript';
import {Duplex, PassThrough, Readable} from 'stream';
import {Reporter} from 'gulp-typescript/release/reporter';
type Callback = () => void;
/**
* This is used to ensure that each project object is not busy when it is to be used
* This prevents the annoying:
* "Error: gulp-typescript: A project cannot be used in two compilations
* at the same time. Create multiple projects with createProject instead."
* @param project The project
* @param reporter The reporter for the project
* @returns {CompileStream} compiled project stream
*/
export function tsCompileQStream(project: Project, reporter?: Reporter): CompileStream {
return new class extends PassThrough implements CompileStream {
public readonly js: Duplex = this;
public readonly dts: Duplex = new PassThrough();
private transformStream: CompileStream;
private signal: Callback;
constructor() {
super({ objectMode: true });
this.on('pipe', this.checkExistingFlow);
}
private checkExistingFlow(src: Readable) {
this.removeListener('pipe', this.checkExistingFlow);
src.unpipe(this);
this.signal = CompileScheduler.scheduleCompilation(project, () => {
this.transformStream = project(reporter).on('finish', () => this.signal());
let compileStream = src.pipe(this.transformStream);
compileStream.js.pipe(this.js);
compileStream.dts.pipe(this.dts);
});
}
};
}
class CompileScheduler {
private static compileGateKeeper: Map<Project, Callback[]> = new Map();
public static scheduleCompilation(project: Project, beginCompilation: Callback): Callback {
let projectQueue = CompileScheduler.compileGateKeeper.get(project);
if (!projectQueue) {
projectQueue = [];
CompileScheduler.compileGateKeeper.set(project, projectQueue);
}
let ret = CompileScheduler.startNext(project);
if (projectQueue.length) {
projectQueue.push(beginCompilation);
} else {
projectQueue.push(ret);
beginCompilation();
}
return ret;
}
private static startNext(project: Project): Callback {
return () => {
let projectQueue = CompileScheduler.compileGateKeeper.get(project);
if (projectQueue.length) {
let nextCompilation = projectQueue.shift();
nextCompilation();
}
};
}
private constructor() {}
}
gulp.task('build', () => {
let project = tsc.createProject('path/to/tsconfig.json');
return project.src()
.pipe(sourcemaps.init())
.pipe(tsCompileQStream(project)) // wrap the project with the function call
.js // you don't need this as the wrapper exposes the js stream by default
.pipe(sourcemaps.write())
.pipe(gulp.dest(project.options.outDir));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment