Skip to content

"tsc -b" with minimal watch capabilities #24465

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 53 commits into from
Jun 9, 2018

Conversation

RyanCavanaugh
Copy link
Member

@RyanCavanaugh RyanCavanaugh commented May 29, 2018

See #22997

Implements tsbuild without --watch. Opening so people have a chance to review non-watch portions sooner. Not planning to merge this unless there is schedule pressure to produce a non-watch build.

I also want to rephrase ~all of the error messages and would like suggestions on any of them

@rbuckton there's a vfs fix in here because we were re-using SourceFile instances even when the underlying file was changed

Open TODOs I'm aware of:

  • Nail down which parts of the tsbuilder API should be exposed (seeking feedback)
  • Determine exactly what --verbose output should be in all situations (seeking feedback)
  • Issue an error when -b appears out of order in a commandline
  • Issue an error when an illegal set of -b flags is provided (e.g. --clean --dry --force, which makes no sense)
  • Add an outFile compilation to the sample projects folder
  • --build --help
  • Support response files in --build mode (do we need this?)

*
* NOTE: do not rename this method as it is intended to align with the same named export of the "fs" module.
*/
public utimesSync(path: string, atime: Date, mtime: Date) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally had this as part of the VFS, the relevant code can be found here: https://gist.github.com/rbuckton/1d064ec108afc0479bc1457d8a46792e#file-filesystem-ts-L596

You should verify the file system isn't read-only before performing updates so that you don't inadvertently modify a copy of the FS shared between multiple tests, i.e.:

if (this.isReadOnly) throw new IOError("EROFS");

throw createIOError("ENOENT");
}
entry.node.atimeMs = +atime;
entry.node.mtimeMs = +mtime;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also set entry.node.ctimeMs = this.time() to set the status change time when you update atimeMs or mtimeMs.

lineStart = false;
}
output += s;
updateLineCountAndPosFor(s);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we are walking now every string we write in the emitter to find lineStarts? why is this needed? do you know the perf impact on the emitter?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't count the lines and the length of the last one, we don't set the line and column correctly for get line and column, resulting in incorrect sourcemaps.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i understand, but how often are these functions called with multi-line text? can we split these to have their own writer function to avoid doing this on every token we write?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably best to discuss this in #24704

/**
* Issue a verbose diagnostic message. No-ops when options.verbose is false.
*/
verbose(diag: DiagnosticMessage, ...args: any[]): void;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in other parts of the system, we have done this through host objects.

*/
function createFileMap<T>(): FileMap<T> {
// tslint:disable-next-line:no-null-keyword
const lookup: { [key: string]: T } = Object.create(/*prototype*/ null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createMap?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ES Maps has better memory characteristics than objects, since they do not hold on to the property name strings.

if (arr.indexOf(element) < 0) {
arr.push(element);
}
if (allKeys.indexOf(key) < 0) allKeys.push(key);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

consider using a map and returning keys, instead of using indexof


function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine) {
const relativePath = getRelativePathFromDirectory(rootDirOfOptions(configFile.options, configFile.options.configFilePath!), inputFileName, /*ignoreCase*/ true);
const outputPath = resolvePath(configFile.options.declarationDir || configFile.options.outDir || getDirectoryPath(configFile.options.configFilePath!), relativePath);
Copy link
Contributor

@mhegazy mhegazy Jun 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like getDeclarationEmitOutputFilePath, can we consolidate?

return changeExtension(outputPath, ".d.ts");
}

function getOutputJavaScriptFileName(inputFileName: string, configFile: ParsedCommandLine) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like getOwnEmitOutputFilePath. can we consolidate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Holding off on these because getOwnEmitOutputFilePath needs a SourceFile and an EmitHost and we have neither at this point.

}

function getOutputFileNames(inputFileName: string, configFile: ParsedCommandLine): ReadonlyArray<string> {
if (configFile.options.outFile) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is out as well.


function getOutFileOutputs(project: ParsedCommandLine): ReadonlyArray<string> {
if (!project.options.outFile) {
throw new Error("Assert - outFile must be set");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debug.fail

throw new Error("Assert - outFile must be set");
}
const outputs: string[] = [];
outputs.push(project.options.outFile);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks a lot like getOutputPathsFor. just use that instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same problem here; those functions were written taking much wider inputs than required or present

}

function isDeclarationFile(fileName: string) {
return fileExtensionIs(fileName, ".d.ts");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, use Extension.Dts instead of ".d.ts"

reportDiagnostic(createCompilerDiagnostic(Diagnostics.A_non_dry_build_would_delete_the_following_files_Colon_0, filesToDelete.map(f => `\r\n * ${f}`).join("")));
}
else {
if (!host.deleteFile) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like this should be the first check

if (host.fileExists(fullPath)) {
return fullPath as ResolvedConfigFileName;
}
reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_0_not_found, fullPath));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this will say something like c:\myconfig.json\tsconfig.json does not exist

};
const program = createProgram(programOptions);

// Don't emit anything in the presence of syntactic errors or options diagnostics
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why? we emit in the presence of errors in tsc.. and why are option errors different from semantic errors?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, we are not building for any errors.. nevermind then.

rootNames: configFile.fileNames,
options: configFile.options
};
const program = createProgram(programOptions);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should not this just call inot the same routine we have in tsc.ts to perform the compilation, why does it have to be different?

}
}

const semanticDiagnostics = [...program.getSemanticDiagnostics()];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why clone it?

@mhegazy
Copy link
Contributor

mhegazy commented Jun 8, 2018

Overall 👍 with some comments:

  • Emitter performance check. Please check the performance of the emitter did not regress from this change
  • Style comments in this PR, we can merge then handle them in a different PR.

@RyanCavanaugh RyanCavanaugh changed the title [WIP/preview] tsbuild without -w "tsc -b" with minimal watch capabilities Jun 8, 2018
@RyanCavanaugh RyanCavanaugh merged commit f4fcb19 into microsoft:master Jun 9, 2018
@RyanCavanaugh RyanCavanaugh deleted the tsbuild branch June 9, 2018 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants