Skip to content

Fix --watch not recompiling sources modified during a compilation - #2850

Merged
nex3 merged 4 commits into
sass:mainfrom
corebonts:fix/rebase-during-watch
Sep 11, 2026
Merged

nex3 merged 4 commits into
sass:mainfrom
corebonts:fix/rebase-during-watch

Conversation

@corebonts

Copy link
Copy Markdown
Contributor

Fixes #2849.

--watch decides whether a stylesheet needs recompiling by comparing the modification time of the source and its dependencies against that of the CSS file it produced (compileStylesheet's ifModified). When a source is modified while a compilation is already in progress that comparison is wrong: the CSS file is written when the compilation finishes, so it is newer than the modification that arrived in the meantime. The source looks up to date, no recompilation happens, and the CSS on disk stays one generation behind, silently. It also survives a restart, since --update makes the same comparison.

This threads the time at which the previous compilation started through to compileStylesheet and uses it in place of the destination's modification time when it is earlier. A source that changed during a compilation is newer than that timestamp, so it is recompiled. The bound is always the earlier of the two, so this can only ever cause more compilations than before, never fewer, and only for sources whose modification time falls between the start of the last compilation and the output it wrote. Startup, one-shot compilations and --update are unaffected, since they pass no timestamp.

The regression test is in the existing recompiles a watched file group. It needs a stylesheet that takes several seconds to compile, since the bug only exists while a compilation is in flight; the delay between the two writes is longer than the polling interval so that the two modifications aren't batched into a single recompilation under --poll. It fails on main in both the --poll and non---poll variants and passes with this change; the rest of test/cli/dart/watch_test.dart and update_test.dart (114 tests) pass with no retries.

One related problem this doesn't address: modifications that land during the initial compilation are dropped outright rather than skipped, because MultiDirWatcher's StreamGroup has no subscriber until watch() starts iterating it, which happens after that compilation finishes.
I wanted to provide a minimal fix to the more common issue we face, and fixing that means attaching the subscription earlier, which changes startup behaviour, so it seemed better as a separate change. But if you want I can include that one as well.

@google-cla

google-cla Bot commented Sep 2, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@corebonts
corebonts force-pushed the fix/rebase-during-watch branch from 16c820a to b07130d Compare September 2, 2026 06:47

@nex3 nex3 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the submission!

Consider instead setting the modification time of the generated file to the time the compilation began. That way, checking the mtime of the source versus the destination will work even across separate runs of the executable, such as when using --update.

});

// Regression test for #2849.
test("when a dependency is modified during a compilation", () async {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's worth having a parallel test for --update as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also thought about modifying the target's date, but I thought that this way it is a smaller change. Implementing the suggestion and adding the additional test.

Sources modified while a compilation is in progress are older than the output that compilation writes when it finishes, so --watch and --update wrongly consider them up to date and skip recompilation. Set the output's modification time to when compilation started so such sources compare as newer, including across restarts.
@corebonts
corebonts force-pushed the fix/rebase-during-watch branch from b07130d to baf77a2 Compare September 5, 2026 11:20
@nex3

nex3 commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

google/dart_cli_pkg#251 and #2859 should fix the CI errors here.

@nex3
nex3 merged commit da84fb5 into sass:main Sep 11, 2026
42 checks passed
@nex3

nex3 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Thanks for the contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

--watch silently skips files modified while a compilation is in progress

2 participants