Conversation
… the watch program TypeScript's `createWatchProgram().close()` stops the file watchers but does not clear `timerToUpdateProgram`. The plugin closes the program in `buildEnd` when Rollup is not in watch mode, so a change to any watched path in the last 250ms of the build leaves the timer armed; it fires after the close, rebuilds the program with a full set of file watchers, and nothing closes those again. `rollup -c` then prints its output and never exits. Track the timers the program arms through the host and cancel the pending ones when the program is closed. Watch mode is unchanged: the program is not closed there until the watcher stops.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rollup Plugin Name:
typescriptThis PR contains:
Are tests included?
Breaking Changes?
List any relevant issue numbers:
nrwl/nx#36794, nrwl/nx#37196
Description
A one-shot
rollup -cwith this plugin sometimes printscreated dist in 380msand never exits. The plugin runs a TypeScript watch program for every build and, when Rollup is not in watch mode, closes it inbuildEnd. TypeScript schedules program updates throughhost.setTimeout(updateProgramWithWatchStatus, 250, "timerToUpdateProgram"), and itsclose()closes the file watchers and clears the resolution timer but not that one (6.0.3;release-5.9has the sameclose()). So a change to any watched path in the 250 ms beforebuildEnd(a source file, atsconfig, apackage.json,node_modules/@types, a directory of a failed lookup) leaves the timer armed; it fires after the close,updateProgramWithWatchStatus()runssynchronizeProgram()on the closed program and installs a new set of file, directory and missing-file watchers.builderProgramis alreadyundefined, so nothing closes them again, and since Rollup's CLI does not callprocess.exitthe process stays up. This is therollup -cchild that Nx's e2e suite finds alive minutes after its output (nrwl/nx#36794); nrwl/nx#37196 works around it on the Nx side by wrapping thetypescriptoption.The change is in
createWatchPrograminsrc/watchProgram.ts: the host'ssetTimeoutandclearTimeoutare wrapped to keep the set of pending timers, and the returned program'sclose()cancels whatever is still pending after TypeScript's own close. Hosts without timers (TypeScript then updates synchronously) are left alone. Watch mode is unchanged: the program is only closed fromcloseWatcher, and a timer is only cancelled by a close.Measured with
dist/cjs/index.jsfrom this branch dropped into a generated Nx React library (rollup -c rollup.config.cjs, TypeScript 6.0.3, Rollup 4.63.5, Node 26.7.0, macOS), onetouchof the entry source file at a fixed offset from spawn; the process lives about 1,050 ms andbuildEndfalls in the 650 to 850 ms band:created …Every hung process holds 192
FSEventWrapand 13StatWatcherhandles (process.getActiveResourcesInfo()onSIGUSR2); no run with this branch holds any.Test:
clears a pending program update when the watch program is closedusesfakeTypescriptwith acreateWatchProgramthat arms a timer through the host the way TypeScript does and records whether it fires after the build; it fails onmaster(the timer fires) and passes here.pnpm testinpackages/typescript: 91 pass, 2 skipped (pre-existing).tsc --noEmit,eslintandprettier --checkclean on the two changed files.The root cause is TypeScript's; clearing
timerToUpdatePrograminclose()there would make the wrapper redundant, but the plugin has to run against every TypeScript its users have installed. Reported upstream as microsoft/TypeScript#64450.