You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
216 lines
6.2 KiB
216 lines
6.2 KiB
"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; |