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; |