Repository navigation
Conversation
robhogan
added this pull request to stack #1947
September 18, 2026 21:05
robhogan
force-pushed
the
robhogan/plugin-change-summaries
branch
from
September 25, 2026 18:04
128f7ac to
6a3fc0e
Compare
robhogan
force-pushed
the
robhogan/plugin-change-summaries
branch
from
September 29, 2026 14:30
6a3fc0e to
5de1b40
Compare
robhogan
force-pushed
the
robhogan/plugin-change-summaries
branch
from
September 29, 2026 14:36
5de1b40 to
aa75dc8
Compare
robhogan
removed this pull request from stack #1947
October 9, 2026 15:33
robhogan
force-pushed
the
robhogan/plugin-change-summaries
branch
from
October 9, 2026 15:34
aa75dc8 to
45d155a
Compare
robhogan
added this pull request to stack #2045
October 9, 2026 15:34
…ange event Stacked on #1952. ## Summary A file map plugin often knows things about a batch of changes that nothing else can work out. The motivating case is Haste - #1952 records the Haste names a resolution looks up, and to invalidate from those a consumer needs to know which names were rebound by a change. It can't derive that from the `ChangeEvent`, which carries paths and modified times, and by the time it sees the event a removed file's name is already gone from the map. `HastePlugin` has it to hand - its `onChanged` is given each removed file's old name and each added file's new one. This gives plugins a way to say so. `FileMapPlugin.onChanged` may now return a summary, and the file map publishes what each plugin returned as `ChangeEvent.pluginChanges`, by plugin name. A plugin that returns nothing is absent, so existing plugins are unaffected - the summary is a third type parameter on `FileMapPlugin` that defaults to `void`. `getPluginChanges(event, plugin)` reads an entry with the plugin's own summary type, so a consumer never writes the name or casts. The summary describes exactly the batch in `changes`. Plugins are already updated synchronously, immediately before the emit, so there's no ordering for a consumer to get wrong - which is the problem with the alternative of asking the plugin afterwards. There are two emit sites: the batched watch path updates plugins inline, and a recrawl updates them inside `#applyFileDelta`, which now returns what they reported along with the changes. The initial build goes through `#applyFileDelta` too but emits nothing, so its summaries go unused. `HastePlugin` is the first user. It reports `changedNames`, the names bound or unbound for any platform by the files added and removed - a bare name, matching what #1952 records. Plugin names now have to be unique across all of a file map's plugins. That was only checked for plugins with a worker, but persisted plugin state is keyed by name for every plugin, so two that shared a name would already have overwritten each other's state. Two things worth knowing: - On a cold start `onChanged` sees every file as added, so `HastePlugin` builds a set of every name for a summary nobody reads. That's nothing where Haste is inert, which is Metro's default, and transient otherwise. If it matters, the alternative is an optional method the file map calls only for a batch it's about to emit. - A modified file reaches plugins in `modifiedFiles` with its new data only, and `HastePlugin.onChanged` doesn't read that list. So an edit that changes a file's Haste name (a docblock, or a global package's `name`) is neither applied to the map nor reported here. That predates this, and can't happen with a path-based `hasteImpl`. `FileSystemChangeAggregator` keeps each file's pre-batch metadata, so giving plugins the old value is feasible, separately. Nothing consumes this yet. ## Test plan ``` yarn jest packages/metro-file-map packages/metro-resolver packages/metro/src/node-haste packages/metro/src/DeltaBundler packages/metro/src/integration_tests packages/metro/src/__tests__ packages/metro/src/Server yarn flow check yarn typecheck-ts yarn verify-api-snapshots ``` - `HastePlugin-test.js`: `onChanged` reports the names bound and unbound, and nothing when no file with a name was added or removed. - `index-test.js`: in watch mode an added and a removed file put both names on the event, read back through `getPluginChanges`, and plugins with nothing to say are absent. A recrawl publishes what plugins reported too. Two plugins sharing a name throw, with or without a worker. Changelog: Internal
robhogan
force-pushed
the
robhogan/plugin-change-summaries
branch
from
October 9, 2026 15:42
45d155a to
d42120c
Compare
This branch has not been deployed
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.
Context
A file map plugin often knows things about a batch of changes that nothing else can work out. For Haste, #1952 records the names a resolution looked up, and invalidating from those means knowing which names a change rebound. The
ChangeEventcarries paths, and by the time a consumer sees it a removed file's name is already gone from the map, butHastePlugin.onChangedhas it to hand:metro/packages/metro-file-map/src/plugins/HastePlugin.js
Lines 241 to 245 in 6dbe979
This change
This lets a plugin's
onChangedreturn a summary, published onChangeEvent.pluginChangesby plugin name. The summary type defaults tovoid, so existing plugins are unaffected.HastePluginreportschangedNames.Plugin names now have to be unique across all plugins, not just those with a worker. Persisted state was already keyed by name, so two sharing a name were already overwriting each other.
Not addressed here: on a cold start
HastePluginbuilds a summary nobody reads (transient, and nothing where Haste is inert), and an edit that changes a file's Haste name is neither applied to the map nor reported, which predates this.Invalidating from the summary is the next PR.
Changelog: Internal
Test plan
New unit tests cover the watch and recrawl paths and duplicate plugin names.