Skip to content

Commit

Permalink
Merge pull request microsoft#4120 from dmichon-msft/typescript-split-…
Browse files Browse the repository at this point in the history
…transpile

[heft-typescript@next] Add "useTranspilerWorker" option
  • Loading branch information
iclanton authored May 22, 2023
2 parents 2181e95 + b67eb49 commit 0654de7
Show file tree
Hide file tree
Showing 18 changed files with 635 additions and 194 deletions.
18 changes: 18 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"type": "node",
"request": "launch",
"name": "Debug Build in Selected Project (Heft)",
"cwd": "${fileDirname}",
"runtimeArgs": [
"--nolazy",
"--inspect-brk",
"${workspaceFolder}/apps/heft/lib/start.js",
"--debug",
"build"
],
"skipFiles": ["<node_internals>/**"],
"outFiles": [],
"sourceMaps": true,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},
{
"name": "Attach",
"type": "node",
Expand Down
2 changes: 2 additions & 0 deletions build-tests/heft-typescript-composite-test/src/indexA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ import(/* webpackChunkName: 'chunk' */ './chunks/ChunkClass')
.catch((e) => {
console.log('Error: ' + e.message);
});

export {};
2 changes: 2 additions & 0 deletions build-tests/heft-typescript-composite-test/src/indexB.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
console.log('dostuff');

export {};
3 changes: 3 additions & 0 deletions build-tests/heft-typescript-composite-test/tsconfig-base.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"noUnusedLocals": true,
"types": ["heft-jest", "webpack-env"],

"isolatedModules": true,
"importsNotUsedAsValues": "error",

"module": "esnext",
"moduleResolution": "node",
"target": "es5",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,7 @@
// "excludeGlobs": [
// "some/path/*.css"
// ]
}
},

"useTranspilerWorker": true
}
2 changes: 1 addition & 1 deletion build-tests/heft-webpack4-everything-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"private": true,
"scripts": {
"build": "heft build --clean",
"start": "heft start",
"start": "heft build-watch --serve",
"_phase:build": "heft run --only build -- --clean",
"_phase:test": "heft run --only test -- --clean"
},
Expand Down
2 changes: 2 additions & 0 deletions build-tests/heft-webpack4-everything-test/src/indexA.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ import(/* webpackChunkName: 'chunk' */ './chunks/ChunkClass')
.catch((e) => {
console.log('Error: ' + e.message);
});

export {};
2 changes: 2 additions & 0 deletions build-tests/heft-webpack4-everything-test/src/indexB.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
console.log('dostuff');

export {};
1 change: 1 addition & 0 deletions build-tests/heft-webpack4-everything-test/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"noUnusedLocals": true,
"types": ["heft-jest", "webpack-env"],
"incremental": true,
"isolatedModules": true,

"module": "esnext",
"moduleResolution": "node",
Expand Down
1 change: 1 addition & 0 deletions common/reviews/api/heft-typescript-plugin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface ITypeScriptConfigurationJson {
// (undocumented)
project?: string;
staticAssetsToCopy?: IStaticAssetsCopyConfiguration;
useTranspilerWorker?: boolean;
}

// @beta (undocumented)
Expand Down
104 changes: 104 additions & 0 deletions heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import { parentPort, workerData } from 'node:worker_threads';

import type * as TTypescript from 'typescript';
import type {
ITranspilationErrorMessage,
ITranspilationRequestMessage,
ITranspilationSuccessMessage,
ITypescriptWorkerData
} from './types';
import type { ExtendedTypeScript } from './internalTypings/TypeScriptInternals';
import { configureProgramForMultiEmit } from './configureProgramForMultiEmit';

const typedWorkerData: ITypescriptWorkerData = workerData;

const ts: ExtendedTypeScript = require(typedWorkerData.typeScriptToolPath);

function handleMessage(message: ITranspilationRequestMessage | false): void {
if (!message) {
process.exit(0);
}

try {
const response: ITranspilationSuccessMessage = runTranspiler(message);
parentPort!.postMessage(response);
} catch (err) {
const errorResponse: ITranspilationErrorMessage = {
requestId: message.requestId,
type: 'error',
result: {
message: err.message,
...Object.fromEntries(Object.entries(err))
}
};
parentPort!.postMessage(errorResponse);
}
}

function runTranspiler(message: ITranspilationRequestMessage): ITranspilationSuccessMessage {
const { requestId, compilerOptions, moduleKindsToEmit, fileNames } = message;

const fullySkipTypeCheck: boolean =
compilerOptions.importsNotUsedAsValues === ts.ImportsNotUsedAsValues.Error;

for (const [option, value] of Object.entries(ts.getDefaultCompilerOptions())) {
if (compilerOptions[option] === undefined) {
compilerOptions[option] = value;
}
}

const { target: rawTarget } = compilerOptions;

for (const option of ts.transpileOptionValueCompilerOptions) {
compilerOptions[option.name] = option.transpileOptionValue;
}

compilerOptions.suppressOutputPathCheck = true;
compilerOptions.skipDefaultLibCheck = true;
compilerOptions.preserveValueImports = true;

const sourceFileByPath: Map<string, TTypescript.SourceFile> = new Map();

for (const fileName of fileNames) {
const sourceText: string | undefined = ts.sys.readFile(fileName);
if (sourceText) {
const sourceFile: TTypescript.SourceFile = ts.createSourceFile(fileName, sourceText, rawTarget!);
sourceFile.hasNoDefaultLib = fullySkipTypeCheck;
sourceFileByPath.set(fileName, sourceFile);
}
}

const newLine: string = ts.getNewLineCharacter(compilerOptions);

const compilerHost: TTypescript.CompilerHost = {
getSourceFile: (fileName: string) => sourceFileByPath.get(fileName),
writeFile: ts.sys.writeFile,
getDefaultLibFileName: () => 'lib.d.ts',
useCaseSensitiveFileNames: () => true,
getCanonicalFileName: (fileName: string) => fileName,
getCurrentDirectory: () => '',
getNewLine: () => newLine,
fileExists: (fileName: string) => sourceFileByPath.has(fileName),
readFile: () => '',
directoryExists: () => true,
getDirectories: () => []
};

const program: TTypescript.Program = ts.createProgram(fileNames, compilerOptions, compilerHost);

configureProgramForMultiEmit(program, ts, moduleKindsToEmit, 'transpile');

const result: TTypescript.EmitResult = program.emit(undefined, undefined, undefined, undefined, undefined);

const response: ITranspilationSuccessMessage = {
requestId,
type: 'success',
result
};

return response;
}

parentPort!.on('message', handleMessage);
Loading

0 comments on commit 0654de7

Please sign in to comment.