Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 1x 1x 1x 1x 1x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 4x 2x | import {CliEngine} from '../cliEngine';
import {DependencyTracker} from './dependencyTracker';
import { Mooltipage } from '../../lib';
import {PipelineIOImpl} from '../../lib/pipeline/standardPipeline';
import {
TrackingCache,
TrackingPipelineIO
} from './trackers';
import {FSWatcher} from 'chokidar';
import {
createReadyFSWatcher,
onAny,
setWatched
} from './FSWatcherUtils';
export class WatchingCliEngine extends CliEngine {
readonly dependencyTracker = new DependencyTracker();
readonly stagedChanges = new Set<string>();
private isWatching = false;
async runApp(): Promise<void> {
// Run initial compilation
await super.runApp();
// enter watch mode
await this.enterWatchMode();
this.cliConsole.log('Entering watch mode - modified files will be rebuilt automatically.');
}
protected createMooltipage(): Mooltipage {
// initialize tracking data
const currentDependencies = new Set<string>();
// create shared callback to collect dependencies from all shared trackers
const trackerCallback = function(resPath: string): void {
currentDependencies.add(resPath);
};
// we are in watch mode, so create a tracking pipeline IO
const inPath = this.args.inPath ?? process.cwd();
const outPath = this.args.outPath ?? process.cwd();
const realIO = new PipelineIOImpl(inPath, outPath);
const trackingIO = new TrackingPipelineIO(realIO, trackerCallback);
// create mooltipage instance
const mooltipage = new Mooltipage({
inPath: this.args.inPath,
outPath: this.args.outPath,
pipelineIO: trackingIO,
formatter: this.args.formatter,
onPageCompiled: async page => {
// update dependencies for page
this.dependencyTracker.setPageDependencies(page.path, currentDependencies);
// reset tracker
currentDependencies.clear();
this.cliConsole.log(`Compiled [${ page.path }].`);
}
});
// inject tracking cache
mooltipage.pipeline.cache.fragmentCache = new TrackingCache(mooltipage.pipeline.cache.fragmentCache, trackerCallback);
return mooltipage;
}
private async enterWatchMode(): Promise<void> {
// create file watcher
const fileWatcher = await createReadyFSWatcher({
disableGlobbing: true,
persistent: true,
ignoreInitial: true,
useFsEvents: true
});
// create timer to apply changes
const applyChangesTimer = setTimeout(() => this.checkAndApplyStagedChanges(fileWatcher), 300);
// watch files
this.watchCurrentFiles(fileWatcher);
// Define callback for FS events
onAny(fileWatcher, [ 'change', 'unlink', 'unlinkDir' ], (_, changedFile) => {
// Only respond to events if we are actually in watch mode
Eif (this.isWatching) {
// add to staged changes
this.stagedChanges.add(changedFile);
// start timer on changes
applyChangesTimer.refresh();
}
});
// enable
this.isWatching = true;
}
private async checkAndApplyStagedChanges(fileWatcher: FSWatcher): Promise<void> {
Eif (this.stagedChanges.size > 0) {
try {
this.isWatching = false;
// get list of files to recompile and clear
const filesToRecompile = new Set(this.stagedChanges);
this.stagedChanges.clear();
// compile changes
await this.compileChangeSet(filesToRecompile);
// reset watched files
this.watchCurrentFiles(fileWatcher);
} catch (e) {
this.cliConsole.error(e);
} finally {
this.stagedChanges.clear();
this.isWatching = true;
}
}
}
private async compileChangeSet(changeSet: Set<string>): Promise<void> {
// list of pages with changes
const changedPages = new Set<string>();
// find pages impacted by each changed file
for (const stagedChange of changeSet) {
// convert raw path back to res path
const stagedChangePath = this.mooltipage.pipeline.pipelineIO.getSourceResPathForAbsolutePath(stagedChange);
// if this is a page, then add directly
Eif (this.dependencyTracker.hasPage(stagedChangePath)) {
changedPages.add(stagedChangePath);
}
// find and add all pages that depend on this
const dependentPages = this.dependencyTracker.getDependentsForResource(stagedChangePath);
for (const dependentPage of dependentPages) {
changedPages.add(dependentPage);
}
// clear cache for staged changes (including resources, not just pages)
this.mooltipage.pipeline.cache.fragmentCache.remove(stagedChangePath);
}
// compile changes
await this.mooltipage.processPages(changedPages);
}
private watchCurrentFiles(fileWatcher: FSWatcher): void {
// get list of absolute paths to all files
const allFiles = Array.from(new Set<string>(Array.from(this.dependencyTracker.getAllTrackedFiles())
.map(trackedFile => this.mooltipage.pipeline.pipelineIO.resolveSourceResource(trackedFile))
));
// watch all files
setWatched(fileWatcher, allFiles);
}
} |