Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fork gulp-typescript tasks to run out-of-process
  • Loading branch information
rbuckton committed May 4, 2018
commit f4ca7ee7676128c410cafbab9ce8525a36e016d1
11 changes: 8 additions & 3 deletions Gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const concat = require("gulp-concat");
const clone = require("gulp-clone");
const newer = require("gulp-newer");
const tsc = require("gulp-typescript");
const tsc_oop = require("./scripts/build/gulp-typescript-oop");
const insert = require("gulp-insert");
const sourcemaps = require("gulp-sourcemaps");
const Q = require("q");
Expand Down Expand Up @@ -409,6 +410,10 @@ function prependCopyright(outputCopyright = !useDebugMode) {
return insert.prepend(outputCopyright ? (copyrightContent || (copyrightContent = fs.readFileSync(copyright).toString())) : "");
}

function getCompilerPath(useBuiltCompiler) {
return useBuiltCompiler ? "./built/local/typescript.js" : "./lib/typescript.js";
}

gulp.task(builtLocalCompiler, /*help*/ false, [servicesFile], () => {
const localCompilerProject = tsc.createProject("src/compiler/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
return localCompilerProject.src()
Expand All @@ -421,7 +426,7 @@ gulp.task(builtLocalCompiler, /*help*/ false, [servicesFile], () => {
});

gulp.task(servicesFile, /*help*/ false, ["lib", "generate-diagnostics"], () => {
const servicesProject = tsc.createProject("src/services/tsconfig.json", getCompilerSettings({ removeComments: false }, /*useBuiltCompiler*/ false));
const servicesProject = tsc_oop.createProject("src/services/tsconfig.json", getCompilerSettings({ removeComments: false }), { typescript: getCompilerPath(/*useBuiltCompiler*/ false) });
const {js, dts} = servicesProject.src()
.pipe(newer(servicesFile))
.pipe(sourcemaps.init())
Expand Down Expand Up @@ -496,7 +501,7 @@ const tsserverLibraryFile = path.join(builtLocalDirectory, "tsserverlibrary.js")
const tsserverLibraryDefinitionFile = path.join(builtLocalDirectory, "tsserverlibrary.d.ts");

gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => {
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }, /*useBuiltCompiler*/ true));
const serverLibraryProject = tsc_oop.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }), { typescript: getCompilerPath(/*useBuiltCompiler*/ true) });
/** @type {{ js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream }} */
const {js, dts} = serverLibraryProject.src()
.pipe(sourcemaps.init())
Expand Down Expand Up @@ -587,7 +592,7 @@ gulp.task("LKG", "Makes a new LKG out of the built js files", ["clean", "dontUse
// Task to build the tests infrastructure using the built compiler
const run = path.join(builtLocalDirectory, "run.js");
gulp.task(run, /*help*/ false, [servicesFile, tsserverLibraryFile], () => {
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
const testProject = tsc_oop.createProject("src/harness/tsconfig.json", getCompilerSettings({}), { typescript: getCompilerPath(/*useBuiltCompiler*/ true) });
return testProject.src()
.pipe(newer(run))
.pipe(sourcemaps.init())
Expand Down
88 changes: 88 additions & 0 deletions scripts/build/gulp-typescript-oop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// @ts-check
const path = require("path");
const child_process = require("child_process");
const tsc = require("gulp-typescript");
const Vinyl = require("vinyl");
const { Duplex, Readable } = require("stream");

/**
* @param {string} tsConfigFileName
* @param {tsc.Settings} settings
* @param {Object} options
* @param {string} [options.typescript]
*/
function createProject(tsConfigFileName, settings, options) {
settings = { ...settings };
options = { ...options };
if (settings.typescript) throw new Error();

const localSettings = { ...settings };
if (options.typescript) {
options.typescript = path.resolve(options.typescript);
localSettings.typescript = require(options.typescript);
}

const project = tsc.createProject(tsConfigFileName, localSettings);
const wrappedProject = /** @type {tsc.Project} */(() => {
const proc = child_process.fork(require.resolve("./main.js"));
/** @type {Duplex & { js?: Readable, dts?: Readable }} */
const compileStream = new Duplex({
objectMode: true,
read() {},
/** @param {*} file */
write(file, encoding, callback) {
proc.send({ method: "write", params: { path: file.path, cwd: file.cwd, base: file.base }});
callback();
},
final(callback) {
proc.send({ method: "final" });
callback();
}
});
const jsStream = compileStream.js = new Readable({
objectMode: true,
read() {}
});
const dtsStream = compileStream.dts = new Readable({
objectMode: true,
read() {}
});
proc.send({ method: "createProject", params: { tsConfigFileName, settings, options } });
proc.on("message", ({ method, params }) => {
if (method === "write") {
const file = new Vinyl({
path: params.path,
cwd: params.cwd,
base: params.base,
contents: Buffer.from(params.contents, "utf8")
});
if (params.sourceMap) file.sourceMap = params.sourceMap
compileStream.push(file);;
if (file.path.endsWith(".d.ts")) {
dtsStream.push(file);
}
else {
jsStream.push(file);
}
}
else if (method === "final") {
compileStream.push(null);
jsStream.push(null);
dtsStream.push(null);
proc.kill();
}
else if (method === "error") {
const error = new Error();
error.name = params.name;
error.message = params.message;
error.stack = params.stack;
compileStream.emit("error", error);
proc.kill();
}
});
return /** @type {*} */(compileStream);
});
return Object.assign(wrappedProject, project);
}

exports.createProject = createProject;
91 changes: 91 additions & 0 deletions scripts/build/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// @ts-check
const path = require("path");
const fs = require("fs");
const tsc = require("gulp-typescript");
const Vinyl = require("vinyl");
const { Readable, Writable } = require("stream");

/** @type {tsc.Project} */
let project;

/** @type {Readable} */
let inputStream;

/** @type {Writable} */
let outputStream;

/** @type {tsc.CompileStream} */
let compileStream;

process.on("message", ({ method, params }) => {
try {
if (method === "createProject") {
const { tsConfigFileName, settings, options } = params;
if (options.typescript) {
settings.typescript = require(options.typescript);
}
project = tsc.createProject(tsConfigFileName, settings);
inputStream = new Readable({
objectMode: true,
read() {}
});
outputStream = new Writable({
objectMode: true,
/**
* @param {*} file
*/
write(file, encoding, callback) {
process.send({
method: "write",
params: {
path: file.path,
cwd: file.cwd,
base: file.base,
contents: file.contents.toString(),
sourceMap: file.sourceMap
}
});
callback();
},
final(callback) {
process.send({ method: "final" });
callback();
}
});
outputStream.on("error", error => {
process.send({
method: "error",
params: {
name: error.name,
message: error.message,
stack: error.stack
}
});
});
compileStream = project();
inputStream.pipe(compileStream).pipe(outputStream);
}
else if (method === "write") {
const file = new Vinyl({
path: params.path,
cwd: params.cwd,
base: params.base
});
file.contents = fs.readFileSync(file.path);
inputStream.push(/** @type {*} */(file));
}
else if (method === "final") {
inputStream.push(null);
}
}
catch (e) {
process.send({
method: "error",
params: {
name: e.name,
message: e.message,
stack: e.stack
}
});
}
});