UNPKG

vite-plugin-dts-build

Version:

A Vite plugin that runs TypeScript build process in a separate worker thread for better performance and efficient incremental builds

183 lines (182 loc) 5.69 kB
"use strict"; const node_path = require("node:path"); const node_worker_threads = require("node:worker_threads"); const node_process = require("node:process"); const ts = require("typescript"); const fsExtra = require("fs-extra"); const { readConfigFile, parseJsonConfigFileContent, createProgram, createEmitAndSemanticDiagnosticsBuilderProgram, createSolutionBuilderHost, createSolutionBuilder, getParsedCommandLineOfConfigFile, getPreEmitDiagnostics, sys, formatDiagnostic, getLineAndCharacterOfPosition, flattenDiagnosticMessageText } = ts; const PROJECT_ROOT = node_process.cwd(); const WORKER_DATA = node_worker_threads.workerData; const tsconfigPath = node_path.resolve( WORKER_DATA.tsconfigPath ?? node_path.join(PROJECT_ROOT, "tsconfig.json") ); const configFile = readConfigFile(tsconfigPath, sys.readFile); if (configFile.error) { throw new Error(errFormatDiagnostic(configFile.error)); } if (WORKER_DATA.include) { configFile.config.include = stringToStringArray(WORKER_DATA.include); } if (WORKER_DATA.exclude) { configFile.config.exclude = stringToStringArray(WORKER_DATA.exclude); } const parsedConfig = parseJsonConfigFileContent( configFile.config, sys, node_path.dirname(tsconfigPath) ); if (parsedConfig.errors.length > 0) { parsedConfig.errors.forEach((error) => { reportDiagnostic(error); }); throw new Error("Failed to parse tsconfig.json"); } const compilerOptions = { incremental: true, // assumeChangesOnlyAffectDirectDependencies: false, declaration: true, // declarationMap: false, emitDeclarationOnly: true, // sourceMap: false, // inlineSourceMap: false, // traceResolution: false, ...parsedConfig.options, ...WORKER_DATA.compilerOptions ?? {} }; const distDir = WORKER_DATA.outDir ?? compilerOptions.declarationDir ?? compilerOptions.outDir ?? node_path.join(PROJECT_ROOT, "dist"); const cacheDir = WORKER_DATA.cacheDir ?? node_path.join(PROJECT_ROOT, ".tsBuildCache"); compilerOptions.declarationDir = cacheDir; const buildOptions = { dry: false, force: false, verbose: false, stopBuildOnErrors: true, ...WORKER_DATA.buildOptions ?? {} }; const checkerMode = compilerOptions?.noEmit === true || buildOptions?.dry === true; if (WORKER_DATA.mode === "compile") { (async () => await runCompile())(); } else { (async () => await runBuild())(); } async function runCompile() { const program = createProgram({ rootNames: parsedConfig.fileNames, options: compilerOptions }); const emitResult = program.emit(); const allDiagnostics = getPreEmitDiagnostics(program).concat( emitResult.diagnostics ); allDiagnostics.forEach((diagnostic) => { if (diagnostic.file && diagnostic.start !== void 0) { const { line, character } = getLineAndCharacterOfPosition( diagnostic.file, diagnostic.start ); const message = flattenDiagnosticMessageText( diagnostic.messageText, "\n" ); console.error( `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}` ); } else { console.error(flattenDiagnosticMessageText(diagnostic.messageText, "\n")); } }); const exitCode = emitResult.emitSkipped ? 1 : 0; return await copyToDist(exitCode); } async function runBuild() { const host = createSolutionBuilderHost( sys, createBuilderProgram, reportDiagnostic, reportSolutionBuilderStatus, reportErrorSummary ); const parseConfigHost = { fileExists: sys.fileExists, readFile: sys.readFile, readDirectory: sys.readDirectory, useCaseSensitiveFileNames: sys.useCaseSensitiveFileNames, getCurrentDirectory: sys.getCurrentDirectory, onUnRecoverableConfigFileDiagnostic: reportDiagnostic }; host.getParsedCommandLine = (fileName) => getParsedCommandLineOfConfigFile( fileName, compilerOptions, parseConfigHost ); const builder = createSolutionBuilder(host, [tsconfigPath], buildOptions); const exitCode = builder.build(); return await copyToDist(exitCode); } function createBuilderProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences) { return createEmitAndSemanticDiagnosticsBuilderProgram( rootNames, { ...options ?? {}, ...compilerOptions }, host, oldProgram, configFileParsingDiagnostics, projectReferences ); } function reportDiagnostic(diagnostic) { console.error(errFormatDiagnostic(diagnostic)); } function reportSolutionBuilderStatus(diagnostic) { console.info(errFormatDiagnostic(diagnostic)); } function reportErrorSummary(errorCount) { if (errorCount !== 0) { console.error(`${errorCount} errors occurred.`); } } function copyToDist(exitCode) { return new Promise((resolve2, reject) => { if (exitCode === 0) { if (checkerMode) { node_worker_threads.parentPort?.postMessage("check-end"); resolve2(); } else { node_worker_threads.parentPort?.postMessage("build-end"); node_worker_threads.parentPort?.once("message", () => { fsExtra.copy(`${cacheDir}/`, `${distDir}/`).then(() => { node_worker_threads.parentPort?.close(); resolve2(); }).catch((error) => { console.error("failed:", error); reject(error); }); }); } } else { reject(); } }); } function stringToStringArray(value) { return typeof value === "string" ? [value] : value; } function errFormatDiagnostic(diagnostic) { return formatDiagnostic(diagnostic, { getCanonicalFileName: (fileName) => fileName, getCurrentDirectory: sys.getCurrentDirectory, getNewLine: () => sys.newLine }); }