Cache results for readFile, fileExists, directory exists, sourceFiles for .d.ts files across the build (only first time)
This commit is contained in:
parent
94d7e30393
commit
6a37fd46fe
|
@ -73,7 +73,6 @@ namespace ts {
|
||||||
// TODO(shkamat): update this after reworking ts build API
|
// TODO(shkamat): update this after reworking ts build API
|
||||||
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
|
||||||
const existingDirectories = createMap<boolean>();
|
const existingDirectories = createMap<boolean>();
|
||||||
|
|
||||||
function getCanonicalFileName(fileName: string): string {
|
function getCanonicalFileName(fileName: string): string {
|
||||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||||
// otherwise use toLowerCase as a canonical form.
|
// otherwise use toLowerCase as a canonical form.
|
||||||
|
@ -84,7 +83,7 @@ namespace ts {
|
||||||
let text: string | undefined;
|
let text: string | undefined;
|
||||||
try {
|
try {
|
||||||
performance.mark("beforeIORead");
|
performance.mark("beforeIORead");
|
||||||
text = system.readFile(fileName, options.charset);
|
text = host.readFile(fileName);
|
||||||
performance.mark("afterIORead");
|
performance.mark("afterIORead");
|
||||||
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
performance.measure("I/O Read", "beforeIORead", "afterIORead");
|
||||||
}
|
}
|
||||||
|
@ -113,7 +112,12 @@ namespace ts {
|
||||||
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
|
||||||
const parentDirectory = getDirectoryPath(directoryPath);
|
const parentDirectory = getDirectoryPath(directoryPath);
|
||||||
ensureDirectoriesExist(parentDirectory);
|
ensureDirectoriesExist(parentDirectory);
|
||||||
system.createDirectory(directoryPath);
|
if (host.createDirectory) {
|
||||||
|
host.createDirectory(directoryPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
system.createDirectory(directoryPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,8 +181,7 @@ namespace ts {
|
||||||
|
|
||||||
const newLine = getNewLineCharacter(options, () => system.newLine);
|
const newLine = getNewLineCharacter(options, () => system.newLine);
|
||||||
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
const realpath = system.realpath && ((path: string) => system.realpath!(path));
|
||||||
|
const host: CompilerHost = {
|
||||||
return {
|
|
||||||
getSourceFile,
|
getSourceFile,
|
||||||
getDefaultLibLocation,
|
getDefaultLibLocation,
|
||||||
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
|
||||||
|
@ -194,8 +197,10 @@ namespace ts {
|
||||||
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
|
||||||
getDirectories: (path: string) => system.getDirectories(path),
|
getDirectories: (path: string) => system.getDirectories(path),
|
||||||
realpath,
|
realpath,
|
||||||
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
|
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth),
|
||||||
|
createDirectory: d => system.createDirectory(d)
|
||||||
};
|
};
|
||||||
|
return host;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
|
export function getPreEmitDiagnostics(program: Program, sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic> {
|
||||||
|
|
|
@ -433,6 +433,7 @@ namespace ts {
|
||||||
const missingRoots = createMap<true>();
|
const missingRoots = createMap<true>();
|
||||||
let globalDependencyGraph: DependencyGraph | undefined;
|
let globalDependencyGraph: DependencyGraph | undefined;
|
||||||
const writeFileName = (s: string) => host.trace && host.trace(s);
|
const writeFileName = (s: string) => host.trace && host.trace(s);
|
||||||
|
let readFileWithCache = (f: string) => host.readFile(f);
|
||||||
|
|
||||||
// Watch state
|
// Watch state
|
||||||
const diagnostics = createFileMap<ReadonlyArray<Diagnostic>>(toPath);
|
const diagnostics = createFileMap<ReadonlyArray<Diagnostic>>(toPath);
|
||||||
|
@ -1072,7 +1073,7 @@ namespace ts {
|
||||||
let priorChangeTime: Date | undefined;
|
let priorChangeTime: Date | undefined;
|
||||||
if (!anyDtsChanged && isDeclarationFile(fileName)) {
|
if (!anyDtsChanged && isDeclarationFile(fileName)) {
|
||||||
// Check for unchanged .d.ts files
|
// Check for unchanged .d.ts files
|
||||||
if (host.fileExists(fileName) && host.readFile(fileName) === content) {
|
if (host.fileExists(fileName) && readFileWithCache(fileName) === content) {
|
||||||
priorChangeTime = host.getModifiedTime(fileName);
|
priorChangeTime = host.getModifiedTime(fileName);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -1182,6 +1183,97 @@ namespace ts {
|
||||||
|
|
||||||
function buildAllProjects(): ExitStatus {
|
function buildAllProjects(): ExitStatus {
|
||||||
if (options.watch) { reportWatchStatus(Diagnostics.Starting_compilation_in_watch_mode); }
|
if (options.watch) { reportWatchStatus(Diagnostics.Starting_compilation_in_watch_mode); }
|
||||||
|
const originalReadFile = host.readFile;
|
||||||
|
const originalFileExists = host.fileExists;
|
||||||
|
const originalDirectoryExists = host.directoryExists;
|
||||||
|
const originalCreateDirectory = host.createDirectory;
|
||||||
|
const originalWriteFile = host.writeFile;
|
||||||
|
const originalGetSourceFile = host.getSourceFile;
|
||||||
|
const readFileCache = createMap<string | false>();
|
||||||
|
const fileExistsCache = createMap<boolean>();
|
||||||
|
const directoryExistsCache = createMap<boolean>();
|
||||||
|
const sourceFileCache = createMap<SourceFile>();
|
||||||
|
const savedReadFileWithCache = readFileWithCache;
|
||||||
|
|
||||||
|
// TODO:: In watch mode as well to use caches for incremental build once we can invalidate caches correctly and have right api
|
||||||
|
// Override readFile for json files and output .d.ts to cache the text
|
||||||
|
readFileWithCache = fileName => {
|
||||||
|
const key = toPath(fileName);
|
||||||
|
const value = readFileCache.get(key);
|
||||||
|
if (value !== undefined) return value || undefined;
|
||||||
|
return setReadFileCache(key, fileName);
|
||||||
|
};
|
||||||
|
const setReadFileCache = (key: Path, fileName: string) => {
|
||||||
|
const newValue = originalReadFile.call(host, fileName);
|
||||||
|
readFileCache.set(key, newValue || false);
|
||||||
|
return newValue;
|
||||||
|
};
|
||||||
|
host.readFile = fileName => {
|
||||||
|
const key = toPath(fileName);
|
||||||
|
const value = readFileCache.get(key);
|
||||||
|
if (value !== undefined) return value; // could be .d.ts from output
|
||||||
|
if (!fileExtensionIs(fileName, Extension.Json)) {
|
||||||
|
return originalReadFile.call(host, fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
return setReadFileCache(key, fileName);
|
||||||
|
};
|
||||||
|
host.getSourceFile = (fileName, languageVersion, onError, shouldCreateNewSourceFile) => {
|
||||||
|
const key = toPath(fileName);
|
||||||
|
const value = sourceFileCache.get(key);
|
||||||
|
if (value) return value;
|
||||||
|
|
||||||
|
const sourceFile = originalGetSourceFile.call(host, fileName, languageVersion, onError, shouldCreateNewSourceFile);
|
||||||
|
if (sourceFile && (isDeclarationFileName(fileName) || fileExtensionIs(fileName, Extension.Json))) {
|
||||||
|
sourceFileCache.set(key, sourceFile);
|
||||||
|
}
|
||||||
|
return sourceFile;
|
||||||
|
};
|
||||||
|
|
||||||
|
// fileExits for any kind of extension
|
||||||
|
host.fileExists = fileName => {
|
||||||
|
const key = toPath(fileName);
|
||||||
|
const value = fileExistsCache.get(key);
|
||||||
|
if (value !== undefined) return value;
|
||||||
|
const newValue = originalFileExists.call(host, fileName);
|
||||||
|
fileExistsCache.set(key, !!newValue);
|
||||||
|
return newValue;
|
||||||
|
};
|
||||||
|
host.writeFile = (fileName, data, writeByteOrderMark, onError, sourceFiles) => {
|
||||||
|
const key = toPath(fileName);
|
||||||
|
fileExistsCache.delete(key);
|
||||||
|
|
||||||
|
const value = readFileCache.get(key);
|
||||||
|
if (value && value !== data) {
|
||||||
|
readFileCache.delete(key);
|
||||||
|
sourceFileCache.delete(key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const sourceFile = sourceFileCache.get(key);
|
||||||
|
if (sourceFile && sourceFile.text !== data) {
|
||||||
|
sourceFileCache.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originalWriteFile.call(host, fileName, data, writeByteOrderMark, onError, sourceFiles);
|
||||||
|
};
|
||||||
|
|
||||||
|
// directoryExists
|
||||||
|
if (originalDirectoryExists && originalCreateDirectory) {
|
||||||
|
host.directoryExists = directory => {
|
||||||
|
const key = toPath(directory);
|
||||||
|
const value = directoryExistsCache.get(key);
|
||||||
|
if (value !== undefined) return value;
|
||||||
|
const newValue = originalDirectoryExists.call(host, directory);
|
||||||
|
directoryExistsCache.set(key, !!newValue);
|
||||||
|
return newValue;
|
||||||
|
};
|
||||||
|
host.createDirectory = directory => {
|
||||||
|
const key = toPath(directory);
|
||||||
|
directoryExistsCache.delete(key);
|
||||||
|
originalCreateDirectory.call(host, directory);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const graph = getGlobalDependencyGraph();
|
const graph = getGlobalDependencyGraph();
|
||||||
reportBuildQueue(graph);
|
reportBuildQueue(graph);
|
||||||
let anyFailed = false;
|
let anyFailed = false;
|
||||||
|
@ -1232,6 +1324,13 @@ namespace ts {
|
||||||
anyFailed = anyFailed || !!(buildResult & BuildResultFlags.AnyErrors);
|
anyFailed = anyFailed || !!(buildResult & BuildResultFlags.AnyErrors);
|
||||||
}
|
}
|
||||||
reportErrorSummary();
|
reportErrorSummary();
|
||||||
|
host.readFile = originalReadFile;
|
||||||
|
host.fileExists = originalFileExists;
|
||||||
|
host.directoryExists = originalDirectoryExists;
|
||||||
|
host.createDirectory = originalCreateDirectory;
|
||||||
|
host.writeFile = originalWriteFile;
|
||||||
|
readFileWithCache = savedReadFileWithCache;
|
||||||
|
host.getSourceFile = originalGetSourceFile;
|
||||||
return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success;
|
return anyFailed ? ExitStatus.DiagnosticsPresent_OutputsSkipped : ExitStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5014,6 +5014,9 @@ namespace ts {
|
||||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||||
createHash?(data: string): string;
|
createHash?(data: string): string;
|
||||||
|
|
||||||
|
// TODO: later handle this in better way in builder host instead once the ap
|
||||||
|
/*@internal*/createDirectory?(directory: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @internal */
|
/* @internal */
|
||||||
|
|
Loading…
Reference in a new issue