Skip to content

Commit 8f11f4a

Browse files
committed
Fork gulp-typescript tasks to run out-of-process
1 parent 2bf01b8 commit 8f11f4a

File tree

3 files changed

+187
-3
lines changed

3 files changed

+187
-3
lines changed

Diff for: Gulpfile.js

+8-3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const concat = require("gulp-concat");
1111
const clone = require("gulp-clone");
1212
const newer = require("gulp-newer");
1313
const tsc = require("gulp-typescript");
14+
const tsc_oop = require("./scripts/build/gulp-typescript-oop");
1415
const insert = require("gulp-insert");
1516
const sourcemaps = require("gulp-sourcemaps");
1617
const Q = require("q");
@@ -409,6 +410,10 @@ function prependCopyright(outputCopyright = !useDebugMode) {
409410
return insert.prepend(outputCopyright ? (copyrightContent || (copyrightContent = fs.readFileSync(copyright).toString())) : "");
410411
}
411412

413+
function getCompilerPath(useBuiltCompiler) {
414+
return useBuiltCompiler ? "./built/local/typescript.js" : "./lib/typescript.js";
415+
}
416+
412417
gulp.task(builtLocalCompiler, /*help*/ false, [servicesFile], () => {
413418
const localCompilerProject = tsc.createProject("src/compiler/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
414419
return localCompilerProject.src()
@@ -421,7 +426,7 @@ gulp.task(builtLocalCompiler, /*help*/ false, [servicesFile], () => {
421426
});
422427

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

498503
gulp.task(tsserverLibraryFile, /*help*/ false, [servicesFile, typesMapJson], (done) => {
499-
const serverLibraryProject = tsc.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }, /*useBuiltCompiler*/ true));
504+
const serverLibraryProject = tsc_oop.createProject("src/server/tsconfig.library.json", getCompilerSettings({ removeComments: false }), { typescript: getCompilerPath(/*useBuiltCompiler*/ true) });
500505
/** @type {{ js: NodeJS.ReadableStream, dts: NodeJS.ReadableStream }} */
501506
const {js, dts} = serverLibraryProject.src()
502507
.pipe(sourcemaps.init())
@@ -587,7 +592,7 @@ gulp.task("LKG", "Makes a new LKG out of the built js files", ["clean", "dontUse
587592
// Task to build the tests infrastructure using the built compiler
588593
const run = path.join(builtLocalDirectory, "run.js");
589594
gulp.task(run, /*help*/ false, [servicesFile, tsserverLibraryFile], () => {
590-
const testProject = tsc.createProject("src/harness/tsconfig.json", getCompilerSettings({}, /*useBuiltCompiler*/ true));
595+
const testProject = tsc_oop.createProject("src/harness/tsconfig.json", getCompilerSettings({}), { typescript: getCompilerPath(/*useBuiltCompiler*/ true) });
591596
return testProject.src()
592597
.pipe(newer(run))
593598
.pipe(sourcemaps.init())

Diff for: scripts/build/gulp-typescript-oop.js

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// @ts-check
2+
const path = require("path");
3+
const child_process = require("child_process");
4+
const tsc = require("gulp-typescript");
5+
const Vinyl = require("vinyl");
6+
const { Duplex, Readable } = require("stream");
7+
8+
/**
9+
* @param {string} tsConfigFileName
10+
* @param {tsc.Settings} settings
11+
* @param {Object} options
12+
* @param {string} [options.typescript]
13+
*/
14+
function createProject(tsConfigFileName, settings, options) {
15+
settings = { ...settings };
16+
options = { ...options };
17+
if (settings.typescript) throw new Error();
18+
19+
const localSettings = { ...settings };
20+
if (options.typescript) {
21+
options.typescript = path.resolve(options.typescript);
22+
localSettings.typescript = require(options.typescript);
23+
}
24+
25+
const project = tsc.createProject(tsConfigFileName, localSettings);
26+
const wrappedProject = /** @type {tsc.Project} */(() => {
27+
const proc = child_process.fork(require.resolve("./main.js"));
28+
/** @type {Duplex & { js?: Readable, dts?: Readable }} */
29+
const compileStream = new Duplex({
30+
objectMode: true,
31+
read() {},
32+
/** @param {*} file */
33+
write(file, encoding, callback) {
34+
proc.send({ method: "write", params: { path: file.path, cwd: file.cwd, base: file.base }});
35+
callback();
36+
},
37+
final(callback) {
38+
proc.send({ method: "final" });
39+
callback();
40+
}
41+
});
42+
const jsStream = compileStream.js = new Readable({
43+
objectMode: true,
44+
read() {}
45+
});
46+
const dtsStream = compileStream.dts = new Readable({
47+
objectMode: true,
48+
read() {}
49+
});
50+
proc.send({ method: "createProject", params: { tsConfigFileName, settings, options } });
51+
proc.on("message", ({ method, params }) => {
52+
if (method === "write") {
53+
const file = new Vinyl({
54+
path: params.path,
55+
cwd: params.cwd,
56+
base: params.base,
57+
contents: Buffer.from(params.contents, "utf8")
58+
});
59+
if (params.sourceMap) file.sourceMap = params.sourceMap
60+
compileStream.push(file);;
61+
if (file.path.endsWith(".d.ts")) {
62+
dtsStream.push(file);
63+
}
64+
else {
65+
jsStream.push(file);
66+
}
67+
}
68+
else if (method === "final") {
69+
compileStream.push(null);
70+
jsStream.push(null);
71+
dtsStream.push(null);
72+
proc.kill();
73+
}
74+
else if (method === "error") {
75+
const error = new Error();
76+
error.name = params.name;
77+
error.message = params.message;
78+
error.stack = params.stack;
79+
compileStream.emit("error", error);
80+
proc.kill();
81+
}
82+
});
83+
return /** @type {*} */(compileStream);
84+
});
85+
return Object.assign(wrappedProject, project);
86+
}
87+
88+
exports.createProject = createProject;

Diff for: scripts/build/main.js

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// @ts-check
2+
const path = require("path");
3+
const fs = require("fs");
4+
const tsc = require("gulp-typescript");
5+
const Vinyl = require("vinyl");
6+
const { Readable, Writable } = require("stream");
7+
8+
/** @type {tsc.Project} */
9+
let project;
10+
11+
/** @type {Readable} */
12+
let inputStream;
13+
14+
/** @type {Writable} */
15+
let outputStream;
16+
17+
/** @type {tsc.CompileStream} */
18+
let compileStream;
19+
20+
process.on("message", ({ method, params }) => {
21+
try {
22+
if (method === "createProject") {
23+
const { tsConfigFileName, settings, options } = params;
24+
if (options.typescript) {
25+
settings.typescript = require(options.typescript);
26+
}
27+
project = tsc.createProject(tsConfigFileName, settings);
28+
inputStream = new Readable({
29+
objectMode: true,
30+
read() {}
31+
});
32+
outputStream = new Writable({
33+
objectMode: true,
34+
/**
35+
* @param {*} file
36+
*/
37+
write(file, encoding, callback) {
38+
process.send({
39+
method: "write",
40+
params: {
41+
path: file.path,
42+
cwd: file.cwd,
43+
base: file.base,
44+
contents: file.contents.toString(),
45+
sourceMap: file.sourceMap
46+
}
47+
});
48+
callback();
49+
},
50+
final(callback) {
51+
process.send({ method: "final" });
52+
callback();
53+
}
54+
});
55+
outputStream.on("error", error => {
56+
process.send({
57+
method: "error",
58+
params: {
59+
name: error.name,
60+
message: error.message,
61+
stack: error.stack
62+
}
63+
});
64+
});
65+
compileStream = project();
66+
inputStream.pipe(compileStream).pipe(outputStream);
67+
}
68+
else if (method === "write") {
69+
const file = new Vinyl({
70+
path: params.path,
71+
cwd: params.cwd,
72+
base: params.base
73+
});
74+
file.contents = fs.readFileSync(file.path);
75+
inputStream.push(/** @type {*} */(file));
76+
}
77+
else if (method === "final") {
78+
inputStream.push(null);
79+
}
80+
}
81+
catch (e) {
82+
process.send({
83+
method: "error",
84+
params: {
85+
name: e.name,
86+
message: e.message,
87+
stack: e.stack
88+
}
89+
});
90+
}
91+
});

0 commit comments

Comments
 (0)