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
4 weeks ago
|
"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;
|