createWatchCompiler.js 1.93 KB
// @flow
import _ from 'lodash';
import type { Compiler } from '../types';

export type WatchCompiler = {
  watch: () => void,
  pause: () => void,
  getWatchOptions: () => {
    aggregateTimeout: number,
    ignored?: RegExp | string,
    poll?: number | boolean,
  },
}

const noop = () => void 0;
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 compiler.constructor.Watching(compiler, watchOptions, noop);
  let watchCompiler = null;

  return {
    watch() {
      if (watchCompiler === null) {
        watchCompiler = createWatcher();
      } else {
        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) {
          // 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 = times; // eslint-disable-line no-param-reassign
          compiler.contextTimestamps = times; // 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 });
    },
  };
}