Implement watch mode#278
Conversation
🦋 Changeset detectedLatest commit: 96351ee The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
56f6254 to
04e1b6e
Compare
|
TODO: Add tests for |
| emitAndReportDiagnosticsTimer = setTimeout(() => { | ||
| emitAndReportDiagnosticsTimer = undefined; | ||
| emitAndReportDiagnostics().catch(logger.logError.bind(logger)); | ||
| }, 250); |
There was a problem hiding this comment.
| * @throws {WriteDtsFileError} | ||
| */ | ||
| async function emitAndReportDiagnostics() { | ||
| logger.clearScreen(); |
There was a problem hiding this comment.
Some users may not want the console cleared. We may need to add the --preserveWatchOutput option.
| logger.logDiagnostics(diagnostics); | ||
| } | ||
| logger.logMessage( | ||
| `Found ${diagnostics.length} error${diagnostics.length === 1 ? '' : 's'}. Watching for file changes.`, |
There was a problem hiding this comment.
This is exactly the same format as tsc messages. Users may find it difficult to distinguish whether a message is from tsc or css-modules-kit...
352dd22 to
615dc2c
Compare
5a3b590 to
4829df7
Compare
31633f2 to
e68d6d3
Compare
2fa9c64 to
bbdd340
Compare
9b62100 to
cba7f2e
Compare
cba7f2e to
96351ee
Compare
| // Workaround for https://github.com/nodejs/node/issues/54450 | ||
| if (platform === 'darwin') await sleep(100); | ||
|
|
||
| const loggerSpy = createLoggerSpy(); | ||
| watcher = await runCMKInWatchMode(fakeParsedArgs({ project: iff.rootDir }), loggerSpy); | ||
| // Workaround for https://github.com/nodejs/node/issues/52601 | ||
| if (platform === 'darwin') await sleep(100); | ||
|
|
||
| // Error when adding a file | ||
| vi.spyOn(watcher.project, 'addFile').mockImplementationOnce(() => { | ||
| throw new Error('test error'); | ||
| }); | ||
| await writeFile(iff.join('src/b.module.css'), '.b_1 { color: red; }'); | ||
| await vi.waitFor(() => { | ||
| expect(loggerSpy.logError).toHaveBeenCalledTimes(1); | ||
| }); | ||
|
|
||
| // Error when changing a file | ||
| vi.spyOn(watcher.project, 'updateFile').mockImplementationOnce(() => { | ||
| throw new Error('test error'); | ||
| }); | ||
| await writeFile(iff.join('src/a.module.css'), '.a_1 { color: blue; }'); | ||
| await vi.waitFor(() => { | ||
| expect(loggerSpy.logError).toHaveBeenCalledTimes(2); | ||
| }); | ||
|
|
||
| // Workaround for https://github.com/paulmillr/chokidar/issues/1399 | ||
| await sleep(100); |
There was a problem hiding this comment.
I never imagined I'd hit three bugs in a single test case. File watching is a abyss :)
ref: nodejs/node#54450, nodejs/node#52601, paulmillr/chokidar#1399
To help others who dare to challenge this abyss, I've left some information behind. Good luck!
|
I've been working on developing this feature since late August, and it's finally complete 🎉 |
close: #178
2025-12-21.19.26.32.mov
Design Notes:
tsc --watchts.sys.watchDirectory. However, it was unclear whether this API would be provided in ts-go, so it was not adopted.runCMKInWatchModefunction.runCMKInWatchModedelegates most processing toProject.Projectis used by both therunCMKfunction for normal mode and therunCMKInWatchModefunction for watch mode. It implements the common logic for both modes.Project, CSS Module files are parsed and inspected, diagnostics are reported, and .d.ts files are emitted.Projectmaintains internal caches for the parsing, checking, and emitting stages. When notified of file changes byrunCMKInWatchMode, it discards the relevant caches.Project#276