import _ from 'lodash' import Watching from 'webpack/lib/Watching' import { Compiler } from 'webpack' export type WatchCompiler = { watch: () => void pause: () => void getWatchOptions: () => { aggregateTimeout: number ignored?: RegExp | string poll?: number | boolean } } const noop = () => undefined export default function createWatchCompiler( compiler: Compiler, watchOptions: {} ): WatchCompiler { // this ugly statement to create a watch compiler is unfortunately necessary, // as webpack clears the file timestamps with the official compiler.watch() const createWatcher = () => new Watching(compiler, watchOptions, noop) let watchCompiler = null return { watch() { if (watchCompiler === null) { watchCompiler = createWatcher() } else { // @ts-ignore const times = compiler.watchFileSystem.watcher.getTimes() // check if we can store some collected file timestamps // the non-empty check is necessary as the times will be reseted after .close() // and we don't want to reset already existing timestamps if (Object.keys(times).length > 0) { const timesMap = new Map( Object.keys(times).map(key => [key, times[key]]) ) // set already collected file timestamps to cache compiled files // webpack will do this only after a file change, but that will not happen when we add or delete files // and this means that we have to test the whole test suite again ... compiler.fileTimestamps = timesMap // eslint-disable-line no-param-reassign compiler.contextTimestamps = timesMap // eslint-disable-line no-param-reassign } watchCompiler.close(() => { watchCompiler = createWatcher() }) } }, pause() { if (watchCompiler !== null && watchCompiler.watcher) { watchCompiler.watcher.pause() } }, getWatchOptions() { // 200 is the default value by webpack return _.get(watchCompiler, 'watchOptions', { aggregateTimeout: 200 }) } } }