diff --git a/packages/webpack-cli/src/webpack-cli.ts b/packages/webpack-cli/src/webpack-cli.ts index 27b1adb51af..2bb7d10974b 100644 --- a/packages/webpack-cli/src/webpack-cli.ts +++ b/packages/webpack-cli/src/webpack-cli.ts @@ -2496,6 +2496,39 @@ class WebpackCLI implements IWebpackCLI { return; } + const isCacheEnabled = Boolean( + this.isMultipleCompiler(compiler) + ? compiler.compilers.some((compiler) => compiler.options.cache) + : compiler.options.cache, + ); + + let needForceShutdown = false; + + if (isCacheEnabled) { + const signals = ["SIGINT", "SIGTERM"]; + + signals.forEach((signal) => { + const listener = () => { + // TODO" remove function check after webpack v4 support drop + if (needForceShutdown || typeof compiler.close !== "function") { + process.exit(); + } + + this.logger.info( + "Gracefully shutting down. To force exit, press ^C again. Please wait...", + ); + + needForceShutdown = true; + + compiler.close(() => { + process.exit(); + }); + }; + + process.on(signal, listener); + }); + } + const isWatch = (compiler: WebpackCompiler): boolean => Boolean( this.isMultipleCompiler(compiler) @@ -2505,7 +2538,15 @@ class WebpackCLI implements IWebpackCLI { if (isWatch(compiler) && this.needWatchStdin(compiler)) { process.stdin.on("end", () => { - process.exit(0); + // TODO: remove on dropping webpack 4 support + if (typeof compiler.close !== "function") { + process.exit(0); + } + + compiler.close(() => { + process.exit(0); + }); + needForceShutdown = true; }); process.stdin.resume(); } diff --git a/test/build/cache/wait.config.js b/test/build/cache/wait.config.js new file mode 100644 index 00000000000..7e4053b60c0 --- /dev/null +++ b/test/build/cache/wait.config.js @@ -0,0 +1,26 @@ +const path = require("path"); +const InfiniteWaitPlugin = require("../../utils/infinite-wait-plugin"); + +module.exports = { + mode: "development", + name: "cache-test-default", + cache: { + type: "filesystem", + buildDependencies: { + config: [__filename], + }, + }, + infrastructureLogging: { + debug: /cache/, + }, + entry: { + app: "./src/main.js", + }, + output: { + filename: "[name].bundle.js", + chunkFilename: "[name].bundle.js", + path: path.resolve(__dirname, "dist"), + publicPath: "/", + }, + plugins: [new InfiniteWaitPlugin()], +}; diff --git a/test/utils/infinite-wait-plugin.js b/test/utils/infinite-wait-plugin.js new file mode 100644 index 00000000000..8c430cf080a --- /dev/null +++ b/test/utils/infinite-wait-plugin.js @@ -0,0 +1,17 @@ +class InfiniteWaitPlugin { + constructor(options = {}) { + this.time = options.time || 10000; + } + apply(compiler) { + compiler.hooks.done.tapPromise("Infinite Wait Plugin", async () => { + await new Promise((resolve) => process.nextTick(resolve)); + await new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, this.time); + }); + }); + } +} + +module.exports = InfiniteWaitPlugin;