|
| 1 | +import { AbortController } from 'node-abort-controller'; |
1 | 2 | import type * as webpack from 'webpack'; |
2 | 3 |
|
3 | 4 | import type { FilesChange } from '../files-change'; |
4 | | -import { consumeFilesChange } from '../files-change'; |
| 5 | +import { aggregateFilesChanges, consumeFilesChange } from '../files-change'; |
5 | 6 | import { getInfrastructureLogger } from '../infrastructure-logger'; |
6 | 7 | import type { ForkTsCheckerWebpackPluginConfig } from '../plugin-config'; |
7 | 8 | import { getPluginHooks } from '../plugin-hooks'; |
@@ -59,49 +60,91 @@ function tapStartToRunWorkers( |
59 | 60 | return; |
60 | 61 | } |
61 | 62 |
|
| 63 | + // get current iteration number |
62 | 64 | const iteration = ++state.iteration; |
63 | 65 |
|
64 | | - let change: FilesChange = {}; |
| 66 | + // abort previous iteration |
| 67 | + if (state.abortController) { |
| 68 | + debug(`Aborting iteration ${iteration - 1}.`); |
| 69 | + state.abortController.abort(); |
| 70 | + } |
| 71 | + |
| 72 | + // create new abort controller for the new iteration |
| 73 | + const abortController = new AbortController(); |
| 74 | + state.abortController = abortController; |
| 75 | + |
| 76 | + let filesChange: FilesChange = {}; |
65 | 77 |
|
66 | 78 | if (state.watching) { |
67 | | - change = consumeFilesChange(compiler); |
| 79 | + filesChange = consumeFilesChange(compiler); |
68 | 80 | log( |
69 | 81 | [ |
70 | 82 | 'Calling reporter service for incremental check.', |
71 | | - ` Changed files: ${JSON.stringify(change.changedFiles)}`, |
72 | | - ` Deleted files: ${JSON.stringify(change.deletedFiles)}`, |
| 83 | + ` Changed files: ${JSON.stringify(filesChange.changedFiles)}`, |
| 84 | + ` Deleted files: ${JSON.stringify(filesChange.deletedFiles)}`, |
73 | 85 | ].join('\n') |
74 | 86 | ); |
75 | 87 | } else { |
76 | 88 | log('Calling reporter service for single check.'); |
77 | 89 | } |
78 | 90 |
|
79 | | - change = await hooks.start.promise(change, compilation); |
| 91 | + filesChange = await hooks.start.promise(filesChange, compilation); |
| 92 | + let aggregatedFilesChange = filesChange; |
| 93 | + if (state.aggregatedFilesChange) { |
| 94 | + aggregatedFilesChange = aggregateFilesChanges([aggregatedFilesChange, filesChange]); |
| 95 | + debug( |
| 96 | + [ |
| 97 | + `Aggregating with previous files change, iteration ${iteration}.`, |
| 98 | + ` Changed files: ${JSON.stringify(aggregatedFilesChange.changedFiles)}`, |
| 99 | + ` Deleted files: ${JSON.stringify(aggregatedFilesChange.deletedFiles)}`, |
| 100 | + ].join('\n') |
| 101 | + ); |
| 102 | + } |
| 103 | + state.aggregatedFilesChange = aggregatedFilesChange; |
| 104 | + |
| 105 | + // submit one at a time for a single compiler |
| 106 | + state.issuesPromise = (state.issuesPromise || Promise.resolve()) |
| 107 | + // resolve to undefined on error |
| 108 | + .catch(() => undefined) |
| 109 | + .then(() => { |
| 110 | + // early return |
| 111 | + if (abortController.signal.aborted) { |
| 112 | + return undefined; |
| 113 | + } |
| 114 | + |
| 115 | + debug(`Submitting the getIssuesWorker to the pool, iteration ${iteration}.`); |
| 116 | + return issuesPool.submit(async () => { |
| 117 | + try { |
| 118 | + debug(`Running the getIssuesWorker, iteration ${iteration}.`); |
| 119 | + const issues = await getIssuesWorker(aggregatedFilesChange, state.watching); |
| 120 | + if (state.aggregatedFilesChange === aggregatedFilesChange) { |
| 121 | + state.aggregatedFilesChange = undefined; |
| 122 | + } |
| 123 | + if (state.abortController === abortController) { |
| 124 | + state.abortController = undefined; |
| 125 | + } |
| 126 | + return issues; |
| 127 | + } catch (error) { |
| 128 | + hooks.error.call(error, compilation); |
| 129 | + return undefined; |
| 130 | + } finally { |
| 131 | + debug(`The getIssuesWorker finished its job, iteration ${iteration}.`); |
| 132 | + } |
| 133 | + }, abortController.signal); |
| 134 | + }); |
80 | 135 |
|
81 | | - debug(`Submitting the getIssuesWorker to the pool, iteration ${iteration}.`); |
82 | | - state.issuesPromise = issuesPool.submit(async () => { |
83 | | - try { |
84 | | - debug(`Running the getIssuesWorker, iteration ${iteration}.`); |
85 | | - return await getIssuesWorker(change, state.watching); |
86 | | - } catch (error) { |
87 | | - hooks.error.call(error, compilation); |
88 | | - return undefined; |
89 | | - } finally { |
90 | | - debug(`The getIssuesWorker finished its job, iteration ${iteration}.`); |
91 | | - } |
92 | | - }); |
93 | 136 | debug(`Submitting the getDependenciesWorker to the pool, iteration ${iteration}.`); |
94 | 137 | state.dependenciesPromise = dependenciesPool.submit(async () => { |
95 | 138 | try { |
96 | 139 | debug(`Running the getDependenciesWorker, iteration ${iteration}.`); |
97 | | - return await getDependenciesWorker(change); |
| 140 | + return await getDependenciesWorker(filesChange); |
98 | 141 | } catch (error) { |
99 | 142 | hooks.error.call(error, compilation); |
100 | 143 | return undefined; |
101 | 144 | } finally { |
102 | 145 | debug(`The getDependenciesWorker finished its job, iteration ${iteration}.`); |
103 | 146 | } |
104 | | - }); |
| 147 | + }); // don't pass abortController.signal because getDependencies() is blocking |
105 | 148 | }); |
106 | 149 | } |
107 | 150 |
|
|
0 commit comments