diff --git a/cli/run/build.ts b/cli/run/build.ts index 54d9daaaed3..38c55e2e05f 100644 --- a/cli/run/build.ts +++ b/cli/run/build.ts @@ -62,6 +62,7 @@ export default async function build( } await Promise.all(outputOptions.map(bundle.write)); + await bundle.close(); if (!silent) { warnings.flush(); stderr(green(`created ${bold(files.join(', '))} in ${bold(ms(Date.now() - start))}`)); diff --git a/cli/run/watch-cli.ts b/cli/run/watch-cli.ts index 1e5aeff9ed7..9629f8fd420 100644 --- a/cli/run/watch-cli.ts +++ b/cli/run/watch-cli.ts @@ -129,6 +129,7 @@ export async function watch(command: any) { if (event.result && event.result.getTimings) { printTimings(event.result.getTimings()); } + event.result.close().catch(error => handleError(error, true)); break; case 'END': diff --git a/docs/02-javascript-api.md b/docs/02-javascript-api.md index aa2e7f1c57b..51092319d03 100755 --- a/docs/02-javascript-api.md +++ b/docs/02-javascript-api.md @@ -10,6 +10,8 @@ The `rollup.rollup` function receives an input options object as parameter and r On a `bundle` object, you can call `bundle.generate` multiple times with different output options objects to generate different bundles in-memory. If you directly want to write them to disk, use `bundle.write` instead. +Once you're finished with the `bundle` object, you should call `bundle.close()`, which will let plugins clean up their external processes or services via the [`closeBundle`](guide/en/#closebundle) hook. + ```javascript const rollup = require('rollup'); @@ -69,6 +71,9 @@ async function build() { // or write the bundle to disk await bundle.write(outputOptions); + + // closes the bundle + await bundle.close(); } build(); @@ -160,7 +165,7 @@ const outputOptions = { ### rollup.watch -Rollup also provides a `rollup.watch` function that rebuilds your bundle when it detects that the individual modules have changed on disk. It is used internally when you run Rollup from the command line with the `--watch` flag. +Rollup also provides a `rollup.watch` function that rebuilds your bundle when it detects that the individual modules have changed on disk. It is used internally when you run Rollup from the command line with the `--watch` flag. Note that when using watch mode via the JavaScript API, it is your responsibility to call `event.result.close()` in response to the `BUNDLE_END` event to allow plugins to clean up resources in the [`closeBundle`](guide/en/#closebundle) hook, see below. ```js const rollup = require('rollup'); @@ -172,9 +177,25 @@ watcher.on('event', event => { // event.code can be one of: // START — the watcher is (re)starting // BUNDLE_START — building an individual bundle + // * event.input will be the input options object if present + // * event.outputFiles cantains an array of the "file" or + // "dir" option values of the generated outputs // BUNDLE_END — finished building a bundle + // * event.input will be the input options object if present + // * event.outputFiles cantains an array of the "file" or + // "dir" option values of the generated outputs + // * event.duration is the build duration in milliseconds + // * event.result contains the bundle object that can be + // used to generate additional outputs by calling + // bundle.generate or bundle.write. This is especially + // important when the watch.skipWrite option is used. + // You should call "event.result.close()" once you are done + // generating outputs, or if you do not generate outputs. + // This will allow plugins to clean up resources via the + // "closeBundle" hook. // END — finished building all bundles // ERROR — encountered an error while bundling + // * event.error contains the error that was thrown }); // stop watching diff --git a/docs/05-plugin-development.md b/docs/05-plugin-development.md index bb709567bcc..29cda7f20fb 100644 --- a/docs/05-plugin-development.md +++ b/docs/05-plugin-development.md @@ -72,9 +72,9 @@ To interact with the build process, your plugin object includes 'hooks'. Hooks a * `sequential`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will wait until the current hook is resolved. * `parallel`: If several plugins implement this hook, all of them will be run in the specified plugin order. If a hook is async, subsequent hooks of this kind will be run in parallel and not wait for the current hook. -Build hooks are run during the build phase, which is triggered by `rollup.rollup(inputOptions)`. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is [options](guide/en/#options), the last one is always [buildEnd](guide/en/#buildend). +Build hooks are run during the build phase, which is triggered by `rollup.rollup(inputOptions)`. They are mainly concerned with locating, providing and transforming input files before they are processed by Rollup. The first hook of the build phase is [`options`](guide/en/#options), the last one is always [`buildEnd`](guide/en/#buildend), unless there is a build error in which case [`closeBundle`](guide/en/#closebundle) will be called after that. -Additionally, in watch mode the [watchChange](guide/en/#watchchange) hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the [closeWatcher](guide/en/#closewatcher) hook will be triggered. +Additionally, in watch mode the [`watchChange`](guide/en/#watchchange) hook can be triggered at any time to notify a new run will be triggered once the current run has generated its outputs. Also, when watcher closes, the [`closeWatcher`](guide/en/#closewatcher) hook will be triggered. See [Output Generation Hooks](guide/en/#output-generation-hooks) for hooks that run during the output generation phase to modify the generated output. @@ -255,7 +255,9 @@ Notifies a plugin whenever rollup has detected a change to a monitored file in ` Output generation hooks can provide information about a generated bundle and modify a build once complete. They work the same way and have the same types as [Build Hooks](guide/en/#build-hooks) but are called separately for each call to `bundle.generate(outputOptions)` or `bundle.write(outputOptions)`. Plugins that only use output generation hooks can also be passed in via the output options and therefore run only for certain outputs. -The first hook of the output generation phase is [outputOptions](guide/en/#outputoptions), the last one is either [generateBundle](guide/en/#generatebundle) if the output was successfully generated via `bundle.generate(...)`, [writeBundle](guide/en/#writebundle) if the output was successfully generated via `bundle.write(...)`, or [renderError](guide/en/#rendererror) if an error occurred at any time during the output generation. +The first hook of the output generation phase is [`outputOptions`](guide/en/#outputoptions), the last one is either [`generateBundle`](guide/en/#generatebundle) if the output was successfully generated via `bundle.generate(...)`, [`writeBundle`](guide/en/#writebundle) if the output was successfully generated via `bundle.write(...)`, or [`renderError`](guide/en/#rendererror) if an error occurred at any time during the output generation. + +Additionally, [`closeBundle`](guide/en/#closebundle) can be called as the very last hook, but it is the responsibility of the User to manually call [`bundle.close()`](guide/en/#rolluprollup) to trigger this. The CLI will always make sure this is the case. #### `augmentChunkHash` Type: `(chunkInfo: ChunkInfo) => string`
@@ -284,6 +286,15 @@ Next Hook: [`renderDynamicImport`](guide/en/#renderdynamicimport) for each dynam Cf. [`output.banner/output.footer`](guide/en/#outputbanneroutputfooter). +#### `closeBundle` +Type: `closeBundle: () => Promise | void`
+Kind: `async, parallel`
+Previous Hook: [`buildEnd`](guide/en/#buildend) if there was a build error, otherwise when [`bundle.close()`](guide/en/#rolluprollup) is called, in which case this would be the last hook to be triggered. + +Can be used to clean up any external service that may be running. Rollup's CLI will make sure this hook is called after each run, but it is the responsibility of users of the JavaScript API to manually call `bundle.close()` once they are done generating bundles. For that reason, any plugin relying on this feature should carefully mention this in its documentation. + +If a plugin wants to retain resources across builds in watch mode, they can check for [`this.meta.watchMode`](guide/en/#thismeta-rollupversion-string-watchmode-boolean) in this hook and perform the necessary cleanup for watch mode in [`closeWatcher`](guide/en/#closewatcher). + #### `footer` Type: `string | (() => string)`
Kind: `async, parallel`
diff --git a/package-lock.json b/package-lock.json index 26b124e2533..80cb209e810 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,25 +14,24 @@ } }, "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.10.tgz", + "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", + "@babel/generator": "^7.12.10", "@babel/helper-module-transforms": "^7.12.1", "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", + "@babel/parser": "^7.12.10", "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.1", "json5": "^2.1.2", "lodash": "^4.17.19", - "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" }, @@ -61,12 +60,12 @@ } }, "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.10.tgz", + "integrity": "sha512-6mCdfhWgmqLdtTkhXjnIz0LcdVCd26wS2JXRtj2XY0u5klDsXBREA/pG5NVOuVnF2LUrBGNFtQkIqqTbblg0ww==", "dev": true, "requires": { - "@babel/types": "^7.12.5", + "@babel/types": "^7.12.10", "jsesc": "^2.5.1", "source-map": "^0.5.0" }, @@ -97,12 +96,12 @@ } }, "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", + "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.10" } }, "@babel/helper-member-expression-to-functions": { @@ -141,12 +140,12 @@ } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", - "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", + "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.12.10" } }, "@babel/helper-replace-supers": { @@ -208,9 +207,9 @@ } }, "@babel/parser": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", - "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.10.tgz", + "integrity": "sha512-PJdRPwyoOqFAWfLytxrWwGrAxghCgh/yTNCYciOz8QgjflA7aZhECPZAa2VUedKg2+QMWkI0L9lynh2SNmNEgA==", "dev": true }, "@babel/template": { @@ -225,17 +224,17 @@ } }, "@babel/traverse": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", - "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.10.tgz", + "integrity": "sha512-6aEtf0IeRgbYWzta29lePeYSk+YAFIC3kyqESeft8o5CkFlYIMX+EQDDWEiAQ9LHOA3d0oHdgrSsID/CKqXJlg==", "dev": true, "requires": { "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", + "@babel/generator": "^7.12.10", "@babel/helper-function-name": "^7.10.4", "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7", + "@babel/parser": "^7.12.10", + "@babel/types": "^7.12.10", "debug": "^4.1.0", "globals": "^11.1.0", "lodash": "^4.17.19" @@ -250,9 +249,9 @@ } }, "@babel/types": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", - "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.10.tgz", + "integrity": "sha512-sf6wboJV5mGyip2hIpDSKsr80RszPinEFjsHTalMxZAZkoQ2/2yQzxlcFN52SJqsyPfLtPmenL4g2KB3KJXPDw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.10.4", @@ -261,9 +260,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", - "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -390,9 +389,9 @@ }, "dependencies": { "estree-walker": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.1.tgz", - "integrity": "sha512-tF0hv+Yi2Ot1cwj9eYHtxC0jB9bmjacjQs6ZBTj82H8JwUywFuc+7E83NWfNMwHXZc11mjfFcVXPe9gEP4B8dg==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", "dev": true } } @@ -509,9 +508,9 @@ "dev": true }, "@types/node": { - "version": "10.17.48", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.48.tgz", - "integrity": "sha512-Agl6xbYP6FOMDeAsr3QVZ+g7Yzg0uhPHWx0j5g4LFdUBHVtqtU+gH660k/lCEe506jJLOGbEzsnqPDTZGJQLag==", + "version": "10.17.49", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.49.tgz", + "integrity": "sha512-PGaJNs5IZz5XgzwJvL/1zRfZB7iaJ5BydZ8/Picm+lUNYoNO9iVTQkVy5eUh0dZDrx3rBOIs3GCbCRmMuYyqwg==", "dev": true }, "@types/parse-json": { @@ -1066,9 +1065,9 @@ "dev": true }, "commander": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true }, "commenting": { @@ -1119,9 +1118,9 @@ } }, "core-js": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.0.tgz", - "integrity": "sha512-W2VYNB0nwQQE7tKS7HzXd7r2y/y2SVJl4ga6oH/dnaLFzM0o2lB2P3zCkWj5Wc/zyMYjtgd5Hmhk0ObkQFZOIA==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.1.tgz", + "integrity": "sha512-9Id2xHY1W7m8hCl8NkhQn5CufmF/WuR30BTRewvCXc1aZd3kMECwNZ69ndLbekKfakw9Rf2Xyc+QR6E7Gg+obg==", "dev": true }, "cosmiconfig": { @@ -1358,13 +1357,13 @@ "dev": true }, "eslint": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz", - "integrity": "sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.15.0.tgz", + "integrity": "sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.1", + "@eslint/eslintrc": "^0.2.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1374,10 +1373,10 @@ "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.0", + "espree": "^7.3.1", "esquery": "^1.2.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", "globals": "^12.1.0", @@ -1589,13 +1588,13 @@ "dev": true }, "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", + "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" }, "dependencies": { @@ -1672,19 +1671,19 @@ "dev": true }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, @@ -1716,12 +1715,12 @@ } }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "fill-range": { @@ -1843,20 +1842,19 @@ "dev": true }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", "dev": true }, "foreground-child": { @@ -1952,13 +1950,10 @@ "dev": true }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true }, "get-symbol-from-current-process-h": { "version": "1.0.2", @@ -2108,15 +2103,15 @@ } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "husky": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", - "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", + "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -2294,9 +2289,9 @@ "dev": true }, "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true }, "interpret": { @@ -2369,9 +2364,9 @@ "dev": true }, "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, "is-number": { @@ -2519,15 +2514,6 @@ "requires": { "aggregate-error": "^3.0.0" } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } } } }, @@ -2706,9 +2692,9 @@ } }, "lint-staged": { - "version": "10.5.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.2.tgz", - "integrity": "sha512-e8AYR1TDlzwB8VVd38Xu2lXDZf6BcshVqKVuBQThDJRaJLobqKnpbm4dkwJ2puypQNbLr9KF/9mfA649mAGvjA==", + "version": "10.5.3", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-10.5.3.tgz", + "integrity": "sha512-TanwFfuqUBLufxCc3RUtFEkFraSPNR3WzWcGF39R3f2J7S9+iF9W0KTVLfSy09lYGmZS5NDCxjNvhGMSJyFCWg==", "dev": true, "requires": { "chalk": "^4.1.0", @@ -2762,12 +2748,44 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3019,6 +3037,15 @@ } } }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "magic-string": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", @@ -3163,13 +3190,10 @@ "dev": true }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "mocha": { "version": "8.2.1", @@ -3497,15 +3521,6 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "string-width": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", @@ -4008,18 +4023,18 @@ } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, "rollup": { - "version": "2.34.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.0.tgz", - "integrity": "sha512-dW5iLvttZzdVehjEuNJ1bWvuMEJjOWGmnuFS82WeKHTGXDkRHQeq/ExdifkSyJv9dLcR86ysKRmrIDyR6O0X8g==", + "version": "2.34.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.34.2.tgz", + "integrity": "sha512-mvtQLqu3cNeoctS+kZ09iOPxrc1P1/Bt1z15enuQ5feyKOdM3MJAVFjjsygurDpSWn530xB4AlA83TWIzRstXA==", "dev": true, "requires": { "fsevents": "~2.1.2" @@ -4047,12 +4062,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true } } }, @@ -4153,13 +4162,36 @@ "graceful-fs": "^4.1.3", "mkdirp": "^0.5.1", "rimraf": "^2.5.2" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "semver": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", - "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", - "dev": true + "version": "7.3.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "semver-compare": { "version": "1.0.0", @@ -4299,17 +4331,6 @@ "rimraf": "^3.0.0", "signal-exit": "^3.0.2", "which": "^2.0.1" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "spdx-compare": { @@ -4648,6 +4669,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -4704,9 +4734,9 @@ } }, "typescript": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz", - "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", + "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", "dev": true }, "uc.micro": { @@ -4954,15 +4984,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", @@ -4981,6 +5002,12 @@ "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", "dev": true }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yaml": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", diff --git a/package.json b/package.json index 1767ceec620..0c2c414d058 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "@rollup/plugin-node-resolve": "^10.0.0", "@rollup/plugin-replace": "^2.3.4", "@types/micromatch": "^4.0.1", - "@types/node": "^10.17.48", + "@types/node": "^10.17.49", "@types/require-relative": "^0.8.0", "@types/signal-exit": "^3.0.0", "@types/yargs-parser": "^15.0.0", @@ -79,18 +79,18 @@ "chokidar": "^3.4.3", "codecov": "^3.8.1", "colorette": "^1.2.1", - "core-js": "^3.8.0", + "core-js": "^3.8.1", "date-time": "^3.1.0", "es5-shim": "^4.5.14", "es6-shim": "^0.35.6", - "eslint": "^7.14.0", + "eslint": "^7.15.0", "eslint-plugin-import": "^2.22.1", - "execa": "^4.1.0", + "execa": "^5.0.0", "fixturify": "^2.1.0", "hash.js": "^1.1.7", - "husky": "^4.3.0", + "husky": "^4.3.6", "is-reference": "^1.2.1", - "lint-staged": "^10.5.2", + "lint-staged": "^10.5.3", "locate-character": "^2.0.5", "magic-string": "^0.25.7", "markdownlint-cli": "^0.25.0", @@ -103,7 +103,7 @@ "pretty-ms": "^7.0.1", "require-relative": "^0.8.7", "requirejs": "^2.3.6", - "rollup": "^2.34.0", + "rollup": "^2.34.2", "rollup-plugin-license": "^2.2.0", "rollup-plugin-string": "^3.0.0", "rollup-plugin-terser": "^7.0.2", @@ -120,7 +120,7 @@ "terser": "^5.5.1", "tslib": "^2.0.3", "tslint": "^6.1.3", - "typescript": "^4.1.2", + "typescript": "^4.1.3", "url-parse": "^1.4.7", "weak-napi": "^2.0.2", "yargs-parser": "^20.2.4" diff --git a/src/rollup/rollup.ts b/src/rollup/rollup.ts index 7224d24a389..c3dffad1299 100644 --- a/src/rollup/rollup.ts +++ b/src/rollup/rollup.ts @@ -2,7 +2,7 @@ import { version as rollupVersion } from 'package.json'; import Bundle from '../Bundle'; import Graph from '../Graph'; import { ensureArray } from '../utils/ensureArray'; -import { errCannotEmitFromOptionsHook, error } from '../utils/error'; +import { errAlreadyClosed, errCannotEmitFromOptionsHook, error } from '../utils/error'; import { writeFile } from '../utils/fs'; import { normalizeInputOptions } from '../utils/options/normalizeInputOptions'; import { normalizeOutputOptions } from '../utils/options/normalizeOutputOptions'; @@ -56,6 +56,7 @@ export async function rollupInternal( err.watchFiles = watchFiles; } await graph.pluginDriver.hookParallel('buildEnd', [err]); + await graph.pluginDriver.hookParallel('closeBundle', []); throw err; } @@ -65,7 +66,17 @@ export async function rollupInternal( const result: RollupBuild = { cache: useCache ? graph.getCache() : undefined, + closed: false, + async close() { + if (result.closed) return; + + result.closed = true; + + await graph.pluginDriver.hookParallel('closeBundle', []); + }, async generate(rawOutputOptions: OutputOptions) { + if (result.closed) return error(errAlreadyClosed()); + return handleGenerateWrite( false, inputOptions, @@ -76,6 +87,8 @@ export async function rollupInternal( }, watchFiles: Object.keys(graph.watchFiles), async write(rawOutputOptions: OutputOptions) { + if (result.closed) return error(errAlreadyClosed()); + return handleGenerateWrite( true, inputOptions, diff --git a/src/rollup/types.d.ts b/src/rollup/types.d.ts index 524a94b2f05..f4c2fa90215 100644 --- a/src/rollup/types.d.ts +++ b/src/rollup/types.d.ts @@ -354,6 +354,7 @@ export interface OutputBundleWithPlaceholders { export interface PluginHooks extends OutputPluginHooks { buildEnd: (this: PluginContext, err?: Error) => Promise | void; buildStart: (this: PluginContext, options: NormalizedInputOptions) => Promise | void; + closeBundle: (this: PluginContext) => Promise | void; closeWatcher: (this: PluginContext) => void; load: LoadHook; moduleParsed: ModuleParsedHook; @@ -416,7 +417,8 @@ export type AsyncPluginHooks = | 'resolveDynamicImport' | 'resolveId' | 'transform' - | 'writeBundle'; + | 'writeBundle' + | 'closeBundle'; export type PluginValueHooks = 'banner' | 'footer' | 'intro' | 'outro'; @@ -451,7 +453,8 @@ export type ParallelPluginHooks = | 'outro' | 'renderError' | 'renderStart' - | 'writeBundle'; + | 'writeBundle' + | 'closeBundle'; interface OutputPluginValueHooks { banner: AddonHook; @@ -769,6 +772,8 @@ export interface RollupOutput { export interface RollupBuild { cache: RollupCache | undefined; + close: () => Promise; + closed: boolean; generate: (outputOptions: OutputOptions) => Promise; getTimings?: () => SerializedTimings; watchFiles: string[]; diff --git a/src/utils/PluginDriver.ts b/src/utils/PluginDriver.ts index b701decca16..b3615af0a40 100644 --- a/src/utils/PluginDriver.ts +++ b/src/utils/PluginDriver.ts @@ -47,6 +47,7 @@ const inputHookNames: { } = { buildEnd: 1, buildStart: 1, + closeBundle: 1, closeWatcher: 1, load: 1, moduleParsed: 1, diff --git a/src/utils/error.ts b/src/utils/error.ts index cd403574271..7147715911d 100644 --- a/src/utils/error.ts +++ b/src/utils/error.ts @@ -37,6 +37,7 @@ export function augmentCodeLocation( } export enum Errors { + ALREADY_CLOSED = 'ALREADY_CLOSED', ASSET_NOT_FINALISED = 'ASSET_NOT_FINALISED', ASSET_NOT_FOUND = 'ASSET_NOT_FOUND', ASSET_SOURCE_ALREADY_SET = 'ASSET_SOURCE_ALREADY_SET', @@ -45,8 +46,9 @@ export enum Errors { CANNOT_EMIT_FROM_OPTIONS_HOOK = 'CANNOT_EMIT_FROM_OPTIONS_HOOK', CHUNK_NOT_GENERATED = 'CHUNK_NOT_GENERATED', DEPRECATED_FEATURE = 'DEPRECATED_FEATURE', - FILE_NOT_FOUND = 'FILE_NOT_FOUND', + EXTERNAL_SYNTHETIC_EXPORTS = 'EXTERNAL_SYNTHETIC_EXPORTS', FILE_NAME_CONFLICT = 'FILE_NAME_CONFLICT', + FILE_NOT_FOUND = 'FILE_NOT_FOUND', INPUT_HOOK_IN_OUTPUT_PLUGIN = 'INPUT_HOOK_IN_OUTPUT_PLUGIN', INVALID_CHUNK = 'INVALID_CHUNK', INVALID_EXPORT_OPTION = 'INVALID_EXPORT_OPTION', @@ -60,12 +62,11 @@ export enum Errors { NO_TRANSFORM_MAP_OR_AST_WITHOUT_CODE = 'NO_TRANSFORM_MAP_OR_AST_WITHOUT_CODE', PLUGIN_ERROR = 'PLUGIN_ERROR', PREFER_NAMED_EXPORTS = 'PREFER_NAMED_EXPORTS', + SYNTHETIC_NAMED_EXPORTS_NEED_NAMESPACE_EXPORT = 'SYNTHETIC_NAMED_EXPORTS_NEED_NAMESPACE_EXPORT', UNEXPECTED_NAMED_IMPORT = 'UNEXPECTED_NAMED_IMPORT', UNRESOLVED_ENTRY = 'UNRESOLVED_ENTRY', UNRESOLVED_IMPORT = 'UNRESOLVED_IMPORT', - VALIDATION_ERROR = 'VALIDATION_ERROR', - EXTERNAL_SYNTHETIC_EXPORTS = 'EXTERNAL_SYNTHETIC_EXPORTS', - SYNTHETIC_NAMED_EXPORTS_NEED_NAMESPACE_EXPORT = 'SYNTHETIC_NAMED_EXPORTS_NEED_NAMESPACE_EXPORT' + VALIDATION_ERROR = 'VALIDATION_ERROR' } export function errAssetNotFinalisedForFileName(name: string) { @@ -377,6 +378,13 @@ export function errFailedValidation(message: string) { }; } +export function errAlreadyClosed() { + return { + code: Errors.ALREADY_CLOSED, + message: 'Bundle is already closed, no more calls to "generate" or "write" are allowed.' + }; +} + export function warnDeprecation( deprecation: string | RollupWarning, activeDeprecation: boolean, diff --git a/test/cli/samples/watch/close-error/_config.js b/test/cli/samples/watch/close-error/_config.js new file mode 100644 index 00000000000..02dbfdd4b9e --- /dev/null +++ b/test/cli/samples/watch/close-error/_config.js @@ -0,0 +1,9 @@ +module.exports = { + description: 'displays errors when closing the watcher', + command: 'rollup -cw', + abortOnStderr(data) { + if (data.includes('[!] (plugin faulty-close) Error: Close bundle failed')) { + return true; + } + } +}; diff --git a/test/cli/samples/watch/close-error/_expected/main.js b/test/cli/samples/watch/close-error/_expected/main.js new file mode 100644 index 00000000000..d862de816a3 --- /dev/null +++ b/test/cli/samples/watch/close-error/_expected/main.js @@ -0,0 +1,3 @@ +var main = 42; + +export default main; diff --git a/test/cli/samples/watch/close-error/main.js b/test/cli/samples/watch/close-error/main.js new file mode 100644 index 00000000000..7a4e8a723a4 --- /dev/null +++ b/test/cli/samples/watch/close-error/main.js @@ -0,0 +1 @@ +export default 42; diff --git a/test/cli/samples/watch/close-error/rollup.config.js b/test/cli/samples/watch/close-error/rollup.config.js new file mode 100644 index 00000000000..f115555c1e4 --- /dev/null +++ b/test/cli/samples/watch/close-error/rollup.config.js @@ -0,0 +1,15 @@ +export default { + input: 'main.js', + plugins: [ + { + name: 'faulty-close', + closeBundle() { + throw new Error('Close bundle failed'); + } + } + ], + output: { + dir: "_actual", + format: "es" + } +}; diff --git a/test/form/samples/supports-core-js/_expected.js b/test/form/samples/supports-core-js/_expected.js index 9637dd2193f..61e5b3c12e9 100644 --- a/test/form/samples/supports-core-js/_expected.js +++ b/test/form/samples/supports-core-js/_expected.js @@ -212,7 +212,7 @@ var shared = createCommonjsModule(function (module) { (module.exports = function (key, value) { return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {}); })('versions', []).push({ - version: '3.8.0', + version: '3.8.1', mode: 'global', copyright: '© 2020 Denis Pushkarev (zloirock.ru)' }); @@ -4363,7 +4363,9 @@ if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNu 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + // ES2015 (in case, if modules with ES2015 Number statics required before): 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + - 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger' + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' + + // ESNext + 'fromString,range' ).split(','), j = 0, key; keys$2.length > j; j++) { if (has(NativeNumber, key = keys$2[j]) && !has(NumberWrapper, key)) { defineProperty$8(NumberWrapper, key, getOwnPropertyDescriptor$6(NativeNumber, key)); @@ -6539,13 +6541,24 @@ var TypedArrayConstructorsList = { Float64Array: 8 }; +var BigIntArrayConstructorsList = { + BigInt64Array: 8, + BigUint64Array: 8 +}; + var isView = function isView(it) { + if (!isObject(it)) return false; var klass = classof(it); - return klass === 'DataView' || has(TypedArrayConstructorsList, klass); + return klass === 'DataView' + || has(TypedArrayConstructorsList, klass) + || has(BigIntArrayConstructorsList, klass); }; var isTypedArray = function (it) { - return isObject(it) && has(TypedArrayConstructorsList, classof(it)); + if (!isObject(it)) return false; + var klass = classof(it); + return has(TypedArrayConstructorsList, klass) + || has(BigIntArrayConstructorsList, klass); }; var aTypedArray = function (it) { diff --git a/test/hooks/index.js b/test/hooks/index.js index bf306c0f31c..30e26bd75a8 100644 --- a/test/hooks/index.js +++ b/test/hooks/index.js @@ -1034,6 +1034,72 @@ describe('hooks', () => { }) .then(bundle => bundle.generate({ format: 'es' }))); + it('supports closeBundle hook', () => { + let closeBundleCalls = 0; + return rollup + .rollup({ + input: 'input', + plugins: [ + loader({ input: `alert('hello')` }), + { + closeBundle() { + closeBundleCalls++; + } + } + ] + }) + .then(bundle => bundle.close()) + .then(() => { + assert.strictEqual(closeBundleCalls, 1); + }); + }); + + it('calls closeBundle hook on build error', () => { + let closeBundleCalls = 0; + return rollup + .rollup({ + input: 'input', + plugins: [ + loader({ input: `alert('hello')` }), + { + buildStart() { + this.error('build start error'); + }, + closeBundle() { + closeBundleCalls++; + } + } + ] + }) + .catch(() => { + assert.strictEqual(closeBundleCalls, 1); + }); + }); + + it('passes errors from closeBundle hook', () => { + let handledError = false; + return rollup + .rollup({ + input: 'input', + plugins: [ + loader({ input: `alert('hello')` }), + { + closeBundle() { + this.error('close bundle error'); + } + } + ] + }) + .then(bundle => bundle.close()) + .catch(error => { + assert.strictEqual(error.message, 'close bundle error'); + handledError = true; + }) + .then(() => { + assert.ok(handledError); + }); + }); + describe('deprecated', () => { it('caches chunk emission in transform hook', () => { let cache; diff --git a/test/misc/sanity-checks.js b/test/misc/sanity-checks.js index 93e4dd738b8..ed11742ed42 100644 --- a/test/misc/sanity-checks.js +++ b/test/misc/sanity-checks.js @@ -1,6 +1,6 @@ const assert = require('assert'); const rollup = require('../../dist/rollup'); -const { loader } = require('../utils.js'); +const { loader, compareError } = require('../utils.js'); describe('sanity checks', () => { it('exists', () => { @@ -237,6 +237,39 @@ describe('sanity checks', () => { ); }); + it('prevents generating and writing from a closed bundle', async () => { + let error = null; + const bundle = await rollup.rollup({ + input: 'x', + plugins: [loader({ x: 'console.log( "x" );' })] + }); + bundle.close(); + // Can be safely called multiple times + bundle.close(); + + try { + await bundle.generate({ file: 'x', format: 'es' }); + } catch (generateError) { + error = generateError; + } + compareError(error, { + code: 'ALREADY_CLOSED', + message: 'Bundle is already closed, no more calls to "generate" or "write" are allowed.' + }); + error = null; + + try { + await bundle.write({ file: 'x', format: 'es' }); + } catch (writeError) { + error = writeError; + } + compareError(error, { + code: 'ALREADY_CLOSED', + message: 'Bundle is already closed, no more calls to "generate" or "write" are allowed.' + }); + error = null; + }); + it('triggers a warning when using output.amd.id together with the "dir" option', async () => { let warning = null; const bundle = await rollup.rollup({