216 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
"use strict";
 | 
						|
 | 
						|
const webpack = require("webpack");
 | 
						|
 | 
						|
const {
 | 
						|
  isColorSupported
 | 
						|
} = require("colorette");
 | 
						|
/** @typedef {import("webpack").Configuration} Configuration */
 | 
						|
 | 
						|
/** @typedef {import("webpack").Compiler} Compiler */
 | 
						|
 | 
						|
/** @typedef {import("webpack").MultiCompiler} MultiCompiler */
 | 
						|
 | 
						|
/** @typedef {import("webpack").Stats} Stats */
 | 
						|
 | 
						|
/** @typedef {import("webpack").MultiStats} MultiStats */
 | 
						|
 | 
						|
/** @typedef {import("../index.js").IncomingMessage} IncomingMessage */
 | 
						|
 | 
						|
/** @typedef {import("../index.js").ServerResponse} ServerResponse */
 | 
						|
 | 
						|
/** @typedef {Configuration["stats"]} StatsOptions */
 | 
						|
 | 
						|
/** @typedef {{ children: Configuration["stats"][] }} MultiStatsOptions */
 | 
						|
 | 
						|
/** @typedef {Exclude<Configuration["stats"], boolean | string | undefined>} NormalizedStatsOptions */
 | 
						|
// TODO remove `color` after dropping webpack v4
 | 
						|
 | 
						|
/** @typedef {{ children: StatsOptions[], colors?: any }} MultiNormalizedStatsOptions */
 | 
						|
 | 
						|
/**
 | 
						|
 * @template {IncomingMessage} Request
 | 
						|
 * @template {ServerResponse} Response
 | 
						|
 * @param {import("../index.js").Context<Request, Response>} context
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
function setupHooks(context) {
 | 
						|
  function invalid() {
 | 
						|
    if (context.state) {
 | 
						|
      context.logger.log("Compilation starting...");
 | 
						|
    } // We are now in invalid state
 | 
						|
    // eslint-disable-next-line no-param-reassign
 | 
						|
 | 
						|
 | 
						|
    context.state = false; // eslint-disable-next-line no-param-reassign, no-undefined
 | 
						|
 | 
						|
    context.stats = undefined;
 | 
						|
  } // @ts-ignore
 | 
						|
 | 
						|
 | 
						|
  const statsForWebpack4 = webpack.Stats && webpack.Stats.presetToOptions;
 | 
						|
  /**
 | 
						|
   * @param {Configuration["stats"]} statsOptions
 | 
						|
   * @returns {NormalizedStatsOptions}
 | 
						|
   */
 | 
						|
 | 
						|
  function normalizeStatsOptions(statsOptions) {
 | 
						|
    if (statsForWebpack4) {
 | 
						|
      if (typeof statsOptions === "undefined") {
 | 
						|
        // eslint-disable-next-line no-param-reassign
 | 
						|
        statsOptions = {};
 | 
						|
      } else if (typeof statsOptions === "boolean" || typeof statsOptions === "string") {
 | 
						|
        // @ts-ignore
 | 
						|
        // eslint-disable-next-line no-param-reassign
 | 
						|
        statsOptions = webpack.Stats.presetToOptions(statsOptions);
 | 
						|
      } // @ts-ignore
 | 
						|
 | 
						|
 | 
						|
      return statsOptions;
 | 
						|
    }
 | 
						|
 | 
						|
    if (typeof statsOptions === "undefined") {
 | 
						|
      // eslint-disable-next-line no-param-reassign
 | 
						|
      statsOptions = {
 | 
						|
        preset: "normal"
 | 
						|
      };
 | 
						|
    } else if (typeof statsOptions === "boolean") {
 | 
						|
      // eslint-disable-next-line no-param-reassign
 | 
						|
      statsOptions = statsOptions ? {
 | 
						|
        preset: "normal"
 | 
						|
      } : {
 | 
						|
        preset: "none"
 | 
						|
      };
 | 
						|
    } else if (typeof statsOptions === "string") {
 | 
						|
      // eslint-disable-next-line no-param-reassign
 | 
						|
      statsOptions = {
 | 
						|
        preset: statsOptions
 | 
						|
      };
 | 
						|
    }
 | 
						|
 | 
						|
    return statsOptions;
 | 
						|
  }
 | 
						|
  /**
 | 
						|
   * @param {Stats | MultiStats} stats
 | 
						|
   */
 | 
						|
 | 
						|
 | 
						|
  function done(stats) {
 | 
						|
    // We are now on valid state
 | 
						|
    // eslint-disable-next-line no-param-reassign
 | 
						|
    context.state = true; // eslint-disable-next-line no-param-reassign
 | 
						|
 | 
						|
    context.stats = stats; // Do the stuff in nextTick, because bundle may be invalidated if a change happened while compiling
 | 
						|
 | 
						|
    process.nextTick(() => {
 | 
						|
      const {
 | 
						|
        compiler,
 | 
						|
        logger,
 | 
						|
        options,
 | 
						|
        state,
 | 
						|
        callbacks
 | 
						|
      } = context; // Check if still in valid state
 | 
						|
 | 
						|
      if (!state) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
 | 
						|
      logger.log("Compilation finished");
 | 
						|
      const isMultiCompilerMode = Boolean(
 | 
						|
      /** @type {MultiCompiler} */
 | 
						|
      compiler.compilers);
 | 
						|
      /**
 | 
						|
       * @type {StatsOptions | MultiStatsOptions | NormalizedStatsOptions | MultiNormalizedStatsOptions}
 | 
						|
       */
 | 
						|
 | 
						|
      let statsOptions;
 | 
						|
 | 
						|
      if (typeof options.stats !== "undefined") {
 | 
						|
        statsOptions = isMultiCompilerMode ? {
 | 
						|
          children:
 | 
						|
          /** @type {MultiCompiler} */
 | 
						|
          compiler.compilers.map(() => options.stats)
 | 
						|
        } : options.stats;
 | 
						|
      } else {
 | 
						|
        statsOptions = isMultiCompilerMode ? {
 | 
						|
          children:
 | 
						|
          /** @type {MultiCompiler} */
 | 
						|
          compiler.compilers.map(child => child.options.stats)
 | 
						|
        } :
 | 
						|
        /** @type {Compiler} */
 | 
						|
        compiler.options.stats;
 | 
						|
      }
 | 
						|
 | 
						|
      if (isMultiCompilerMode) {
 | 
						|
        /** @type {MultiNormalizedStatsOptions} */
 | 
						|
        statsOptions.children =
 | 
						|
        /** @type {MultiStatsOptions} */
 | 
						|
        statsOptions.children.map(
 | 
						|
        /**
 | 
						|
         * @param {StatsOptions} childStatsOptions
 | 
						|
         * @return {NormalizedStatsOptions}
 | 
						|
         */
 | 
						|
        childStatsOptions => {
 | 
						|
          // eslint-disable-next-line no-param-reassign
 | 
						|
          childStatsOptions = normalizeStatsOptions(childStatsOptions);
 | 
						|
 | 
						|
          if (typeof childStatsOptions.colors === "undefined") {
 | 
						|
            // eslint-disable-next-line no-param-reassign
 | 
						|
            childStatsOptions.colors = isColorSupported;
 | 
						|
          }
 | 
						|
 | 
						|
          return childStatsOptions;
 | 
						|
        });
 | 
						|
      } else {
 | 
						|
        /** @type {NormalizedStatsOptions} */
 | 
						|
        statsOptions = normalizeStatsOptions(
 | 
						|
        /** @type {StatsOptions} */
 | 
						|
        statsOptions);
 | 
						|
 | 
						|
        if (typeof statsOptions.colors === "undefined") {
 | 
						|
          statsOptions.colors = isColorSupported;
 | 
						|
        }
 | 
						|
      } // TODO webpack@4 doesn't support `{ children: [{ colors: true }, { colors: true }] }` for stats
 | 
						|
 | 
						|
 | 
						|
      if (
 | 
						|
      /** @type {MultiCompiler} */
 | 
						|
      compiler.compilers && statsForWebpack4) {
 | 
						|
        /** @type {MultiNormalizedStatsOptions} */
 | 
						|
        statsOptions.colors =
 | 
						|
        /** @type {MultiNormalizedStatsOptions} */
 | 
						|
        statsOptions.children.some(
 | 
						|
        /**
 | 
						|
         * @param {StatsOptions} child
 | 
						|
         */
 | 
						|
        // @ts-ignore
 | 
						|
        child => child.colors);
 | 
						|
      }
 | 
						|
 | 
						|
      const printedStats = stats.toString(statsOptions); // Avoid extra empty line when `stats: 'none'`
 | 
						|
 | 
						|
      if (printedStats) {
 | 
						|
        // eslint-disable-next-line no-console
 | 
						|
        console.log(printedStats);
 | 
						|
      } // eslint-disable-next-line no-param-reassign
 | 
						|
 | 
						|
 | 
						|
      context.callbacks = []; // Execute callback that are delayed
 | 
						|
 | 
						|
      callbacks.forEach(
 | 
						|
      /**
 | 
						|
       * @param {(...args: any[]) => Stats | MultiStats} callback
 | 
						|
       */
 | 
						|
      callback => {
 | 
						|
        callback(stats);
 | 
						|
      });
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  context.compiler.hooks.watchRun.tap("webpack-dev-middleware", invalid);
 | 
						|
  context.compiler.hooks.invalid.tap("webpack-dev-middleware", invalid);
 | 
						|
  context.compiler.hooks.done.tap("webpack-dev-middleware", done);
 | 
						|
}
 | 
						|
 | 
						|
module.exports = setupHooks; |