diff --git a/package.json b/package.json index 0d4c9fb2..f667fdd4 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "1.0.11", "vscode-uri": "^3.0.8", - "which": "^4.0.0" + "which": "^4.0.0", + "why-is-node-running": "^2.2.2" } } diff --git a/rollup-exit-plugin.js b/rollup-exit-plugin.js new file mode 100644 index 00000000..10464343 --- /dev/null +++ b/rollup-exit-plugin.js @@ -0,0 +1,47 @@ +import whyIsNodeRunning from 'why-is-node-running'; + +let runningBundles = 0; + +/** + * @param {string} name + * @param {number} maxWaitTime Maximum number of seconds to wait for Rollup to exit before force-exiting + * @returns {{closeBundle(): void, buildStart(): void, name: string}} + */ +export const rollupForceExit = (name, maxWaitTime = 60) => { + return { + /** @this {import('rollup').PluginContext} */ + buildStart() { + if (this.meta.watchMode) { + return; + } + + runningBundles++; + this.info(`${name}: Starting build, ${runningBundles} build(s) running`); + }, + /** @this {import('rollup').PluginContext} */ + closeBundle() { + if (this.meta.watchMode) { + return; + } + + runningBundles--; + const timeout = setTimeout(() => { + if (runningBundles === 0) { + this.info( + `${name}: Rollup is now done, but did not exit before ${maxWaitTime} seconds, force exiting...`, + ); + whyIsNodeRunning(); + setTimeout(() => process.exit(0)); + } else { + this.info( + `${name}: Rollup is still working on another build process, waiting for ${runningBundles} running bundle(s) before force exit`, + ); + } + }, maxWaitTime * 1000); + // Allow the NodeJS process to finish without waiting for the timeout, using it only as a fallback for + // otherwise hanging Rollup processes + timeout.unref(); + }, + name: 'force-close', + }; +}; diff --git a/rollup.config.ts b/rollup.config.ts index 86e21935..3cfe0093 100644 --- a/rollup.config.ts +++ b/rollup.config.ts @@ -3,6 +3,7 @@ import terser from '@rollup/plugin-terser'; import resolve from '@rollup/plugin-node-resolve'; import commonJS from '@rollup/plugin-commonjs'; import typescript from '@rollup/plugin-typescript'; +import { rollupForceExit } from './rollup-exit-plugin.js'; export default defineConfig({ input: 'src/cli.ts', @@ -26,5 +27,6 @@ export default defineConfig({ commonJS(), resolve(), typescript(), + rollupForceExit('rollup-build', 5), ], });