fix(@ngtools/webpack): support watching file replacements

This commit is contained in:
Charles Lyding 2018-07-09 12:05:35 -04:00 committed by Hans
parent 56fb5ebce0
commit d09d739b60
2 changed files with 98 additions and 18 deletions

View File

@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be * Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import { dirname, normalize, resolve, virtualFs } from '@angular-devkit/core'; import { Path, dirname, normalize, resolve, virtualFs } from '@angular-devkit/core';
import { NodeJsSyncHost } from '@angular-devkit/core/node'; import { NodeJsSyncHost } from '@angular-devkit/core/node';
import { ChildProcess, ForkOptions, fork } from 'child_process'; import { ChildProcess, ForkOptions, fork } from 'child_process';
import * as fs from 'fs'; import * as fs from 'fs';
@ -617,8 +617,21 @@ export class AngularCompilerPlugin {
this._compilerHost, this._compilerHost,
); );
compilerWithFileSystems.inputFileSystem = inputDecorator; compilerWithFileSystems.inputFileSystem = inputDecorator;
let replacements: Map<Path, Path> | undefined;
if (this._options.hostReplacementPaths) {
replacements = new Map();
for (const replace in this._options.hostReplacementPaths) {
replacements.set(
normalize(replace),
normalize(this._options.hostReplacementPaths[replace]),
);
}
}
compilerWithFileSystems.watchFileSystem = new VirtualWatchFileSystemDecorator( compilerWithFileSystems.watchFileSystem = new VirtualWatchFileSystemDecorator(
inputDecorator, inputDecorator,
replacements,
); );
}); });

View File

@ -5,6 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be * Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import { Path, getSystemPath, normalize } from '@angular-devkit/core';
import { Stats } from 'fs'; import { Stats } from 'fs';
import { WebpackCompilerHost } from './compiler_host'; import { WebpackCompilerHost } from './compiler_host';
import { Callback, InputFileSystem, NodeWatchFileSystemInterface } from './webpack'; import { Callback, InputFileSystem, NodeWatchFileSystemInterface } from './webpack';
@ -105,26 +106,52 @@ export class VirtualFileSystemDecorator implements InputFileSystem {
} }
export class VirtualWatchFileSystemDecorator extends NodeWatchFileSystem { export class VirtualWatchFileSystemDecorator extends NodeWatchFileSystem {
constructor(private _virtualInputFileSystem: VirtualFileSystemDecorator) { constructor(
private _virtualInputFileSystem: VirtualFileSystemDecorator,
private _replacements?: Map<Path, Path>,
) {
super(_virtualInputFileSystem); super(_virtualInputFileSystem);
} }
watch( watch(
files: any, // tslint:disable-line:no-any files: string[],
dirs: any, // tslint:disable-line:no-any dirs: string[],
missing: any, // tslint:disable-line:no-any missing: string[],
startTime: any, // tslint:disable-line:no-any startTime: number | undefined,
options: any, // tslint:disable-line:no-any options: {},
callback: any, // tslint:disable-line:no-any callback: any, // tslint:disable-line:no-any
callbackUndelayed: any, // tslint:disable-line:no-any callbackUndelayed: (filename: string, timestamp: number) => void,
) { ) {
const reverseReplacements = new Map<string, string>();
const reverseTimestamps = (map: Map<string, number>) => {
for (const entry of Array.from(map.entries())) {
const original = reverseReplacements.get(entry[0]);
if (original) {
map.set(original, entry[1]);
map.delete(entry[0]);
}
}
return map;
};
const newCallbackUndelayed = (filename: string, timestamp: number) => {
const original = reverseReplacements.get(filename);
if (original) {
this._virtualInputFileSystem.purge(original);
callbackUndelayed(original, timestamp);
} else {
callbackUndelayed(filename, timestamp);
}
};
const newCallback = ( const newCallback = (
err: any, // tslint:disable-line:no-any err: Error | null,
filesModified: any, // tslint:disable-line:no-any filesModified: string[],
contextModified: any, // tslint:disable-line:no-any contextModified: string[],
missingModified: any, // tslint:disable-line:no-any missingModified: string[],
fileTimestamps: { [k: string]: number }, fileTimestamps: Map<string, number>,
contextTimestamps: { [k: string]: number }, contextTimestamps: Map<string, number>,
) => { ) => {
// Update fileTimestamps with timestamps from virtual files. // Update fileTimestamps with timestamps from virtual files.
const virtualFilesStats = this._virtualInputFileSystem.getVirtualFilesPaths() const virtualFilesStats = this._virtualInputFileSystem.getVirtualFilesPaths()
@ -132,11 +159,51 @@ export class VirtualWatchFileSystemDecorator extends NodeWatchFileSystem {
path: fileName, path: fileName,
mtime: +this._virtualInputFileSystem.statSync(fileName).mtime, mtime: +this._virtualInputFileSystem.statSync(fileName).mtime,
})); }));
virtualFilesStats.forEach(stats => fileTimestamps[stats.path] = +stats.mtime); virtualFilesStats.forEach(stats => fileTimestamps.set(stats.path, +stats.mtime));
callback(err, filesModified, contextModified, missingModified, fileTimestamps, callback(
contextTimestamps); err,
filesModified.map(value => reverseReplacements.get(value) || value),
contextModified.map(value => reverseReplacements.get(value) || value),
missingModified.map(value => reverseReplacements.get(value) || value),
reverseTimestamps(fileTimestamps),
reverseTimestamps(contextTimestamps),
);
}; };
return super.watch(files, dirs, missing, startTime, options, newCallback, callbackUndelayed); const mapReplacements = (original: string[]): string[] => {
if (!this._replacements) {
return original;
}
const replacements = this._replacements;
return original.map(file => {
const replacement = replacements.get(normalize(file));
if (replacement) {
const fullReplacement = getSystemPath(replacement);
reverseReplacements.set(fullReplacement, file);
return fullReplacement;
} else {
return file;
}
});
};
const watcher = super.watch(
mapReplacements(files),
mapReplacements(dirs),
mapReplacements(missing),
startTime,
options,
newCallback,
newCallbackUndelayed,
);
return {
close: () => watcher.close(),
pause: () => watcher.pause(),
getFileTimestamps: () => reverseTimestamps(watcher.getFileTimestamps()),
getContextTimestamps: () => reverseTimestamps(watcher.getContextTimestamps()),
};
} }
} }