Fork gulp-typescript tasks to run out-of-process

This commit is contained in:
Ron Buckton
2018-05-04 10:45:16 -07:00
parent a089297ca3
commit f4ca7ee767
3 changed files with 187 additions and 3 deletions

View File

@@ -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");
@@ -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()
@@ -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())
@@ -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())
@@ -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())

View File

@@ -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
scripts/build/main.js Normal file
View File

@@ -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
}
});
}
});