Skip to content
This repository was archived by the owner on Apr 4, 2025. It is now read-only.

feat(@ngtools/webpack): resolve all file requests with the virtual fs #887

Merged
merged 2 commits into from
May 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 82 additions & 26 deletions packages/ngtools/webpack/src/compiler_host.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,38 +74,78 @@ export class VirtualDirStats extends VirtualStats {

export class VirtualFileStats extends VirtualStats {
private _sourceFile: ts.SourceFile | null;
constructor(_fileName: string, private _content: string) {
private _content: string | null;
private _bufferContent: virtualFs.FileBuffer | null;

constructor(_fileName: string) {
super(_fileName);
}

get content() { return this._content; }
static createFromString(_fileName: string, _content: string) {
const stats = new VirtualFileStats(_fileName);
stats.content = _content;

return stats;
}

static createFromBuffer(_fileName: string, _buffer: virtualFs.FileBuffer) {
const stats = new VirtualFileStats(_fileName);
stats.bufferContent = _buffer;

return stats;
}

get content() {
if (!this._content && this.bufferContent) {
this._content = virtualFs.fileBufferToString(this.bufferContent);
}

return this._content || '';
}
set content(v: string) {
this._content = v;
this._mtime = new Date();
this._sourceFile = null;
this._bufferContent = null;
this.resetMetadata();
}

get bufferContent() {
if (!this._bufferContent && this._content) {
this._bufferContent = virtualFs.stringToFileBuffer(this._content);
}

return this._bufferContent || virtualFs.stringToFileBuffer('');
}
set bufferContent(buf: virtualFs.FileBuffer) {
this._bufferContent = buf;
this._content = null;
this.resetMetadata();
}

setSourceFile(sourceFile: ts.SourceFile) {
this._sourceFile = sourceFile;
}
getSourceFile(languageVersion: ts.ScriptTarget, setParentNodes: boolean) {
if (!this._sourceFile) {
// console.log(this._path)
this._sourceFile = ts.createSourceFile(
workaroundResolve(this._path),
this._content,
this.content,
languageVersion,
setParentNodes);
}

return this._sourceFile;
}

private resetMetadata(): void {
this._mtime = new Date();
this._sourceFile = null;
}

isFile() { return true; }

get size() { return this._content.length; }
get size() { return this.content.length; }
}


export class WebpackCompilerHost implements ts.CompilerHost {
private _syncHost: virtualFs.SyncDelegateHost;
private _files: {[path: string]: VirtualFileStats | null} = Object.create(null);
Expand Down Expand Up @@ -149,8 +189,8 @@ export class WebpackCompilerHost implements ts.CompilerHost {
}
}

private _setFileContent(fileName: Path, content: string) {
this._files[fileName] = new VirtualFileStats(fileName, content);
private _cacheFile(fileName: string, stats: VirtualFileStats) {
this._files[fileName] = stats;

let p = dirname(fileName);
while (p && !this._directories[p]) {
Expand Down Expand Up @@ -211,33 +251,48 @@ export class WebpackCompilerHost implements ts.CompilerHost {
}

readFile(fileName: string): string | undefined {
const stats = this.findVirtualFile(fileName);

return stats && stats.content;
}

readFileBuffer(fileName: string): Buffer | undefined {
const stats = this.findVirtualFile(fileName);
if (stats) {
const buffer = Buffer.from(stats.bufferContent);

return buffer;
}
}

private findVirtualFile(fileName: string): VirtualFileStats | undefined {
const p = this.resolve(fileName);

const stats = this._files[p];
if (!stats) {
try {
const result = virtualFs.fileBufferToString(this._syncHost.read(p));
if (result !== undefined) {
if (this._cache) {
this._setFileContent(p, result);
}
if (stats) {
return stats;
}

try {
const fileBuffer = this._syncHost.read(p);
if (fileBuffer) {
const stats = VirtualFileStats.createFromBuffer(p, fileBuffer);
if (this._cache) {
this._cacheFile(p, stats);
}

return result;
} catch (e) {
return undefined;
return stats;
}
} catch (e) {
return undefined;
}

return stats.content;
}

// Does not delegate, use with `fileExists/directoryExists()`.
stat(path: string): VirtualStats {
stat(path: string): VirtualStats | null {
const p = this.resolve(path);
const stats = this._files[p] || this._directories[p];
if (!stats) {
throw new Error(`File not found: ${JSON.stringify(p)}`);
return this._syncHost.stat(p) as VirtualStats | null;
}

return stats;
Expand Down Expand Up @@ -345,7 +400,8 @@ export class WebpackCompilerHost implements ts.CompilerHost {
_sourceFiles?: ReadonlyArray<ts.SourceFile>,
): void => {
const p = this.resolve(fileName);
this._setFileContent(p, data);
const stats = VirtualFileStats.createFromString(p, data);
this._cacheFile(p, stats);
};
}

Expand Down
13 changes: 6 additions & 7 deletions packages/ngtools/webpack/src/virtual_file_system_decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,16 @@ export class VirtualFileSystemDecorator implements InputFileSystem {
private _webpackCompilerHost: WebpackCompilerHost,
) { }

// We only need to intercept calls to individual files that are present in WebpackCompilerHost.
private _readFileSync(path: string): string | null {
if (this._webpackCompilerHost.fileExists(path, false)) {
return this._webpackCompilerHost.readFile(path) || null;
private _readFileSync(path: string): Buffer | null {
if (this._webpackCompilerHost.fileExists(path)) {
return this._webpackCompilerHost.readFileBuffer(path) || null;
}

return null;
}

private _statSync(path: string): Stats | null {
if (this._webpackCompilerHost.fileExists(path, false)) {
if (this._webpackCompilerHost.fileExists(path)) {
return this._webpackCompilerHost.stat(path);
}

Expand All @@ -52,7 +51,7 @@ export class VirtualFileSystemDecorator implements InputFileSystem {
this._inputFileSystem.readdir(path, callback);
}

readFile(path: string, callback: Callback<string>): void {
readFile(path: string, callback: Callback<string | Buffer>): void {
const result = this._readFileSync(path);
if (result) {
callback(null, result);
Expand All @@ -79,7 +78,7 @@ export class VirtualFileSystemDecorator implements InputFileSystem {
return this._inputFileSystem.readdirSync(path);
}

readFileSync(path: string): string {
readFileSync(path: string): string | Buffer {
const result = this._readFileSync(path);

return result || this._inputFileSystem.readFileSync(path);
Expand Down
4 changes: 2 additions & 2 deletions packages/ngtools/webpack/src/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ export interface NormalModuleFactoryRequest {
export interface InputFileSystem {
stat(path: string, callback: Callback<Stats>): void;
readdir(path: string, callback: Callback<string[]>): void;
readFile(path: string, callback: Callback<string>): void;
readFile(path: string, callback: Callback<string | Buffer>): void;
// tslint:disable-next-line:no-any
readJson(path: string, callback: Callback<any>): void;
readlink(path: string, callback: Callback<string>): void;
statSync(path: string): Stats;
readdirSync(path: string): string[];
readFileSync(path: string): string;
readFileSync(path: string): string | Buffer;
// tslint:disable-next-line:no-any
readJsonSync(path: string): any;
readlinkSync(path: string): string;
Expand Down