Repository navigation
Conversation
#2000 replaced the watchers' globs with `included`, comparing extensions using `path.extname`. That isn't quite what the `**/*.<ext>` globs did with `dot: true` - `path.extname('.env')` is `''`, so `.env` no longer matches an `env` extension, and a multi-part extension like `d.ts` never matches. That's a regression for Expo, which adds `env` to `watcher.additionalExts` so that editing `.env` triggers a reload: https://github.com/expo/expo/blob/7c9b0878c1942d24552adfab7de396c9e4a69103/packages/@expo/metro-config/src/ExpoMetroConfig.ts#L345 This matches an extension when the basename ends with `.` followed by that extension, after any dot, which is what the globs matched. Changelog: Internal (#2000 is unreleased) Test plan: Extended `common-test.js` with dotfile and multi-part extension cases. Compared against `micromatch.some(path, globs, {dot: true})` with the globs Metro used to build, on 21 edge-case paths (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, ...), with no mismatches. Found by Expo's `hmr-env-vars` E2E test failing on the port of #2000 to Expo's file map, expo/expo#51093, which carries the same fix.
1 of 3 tasks
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Port of react/metro#2000 + react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How This replaces the watchers' `globs` option with `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, so `.env` matches `env` and `foo.d.ts` matches `d.ts`. It also removes the watchers' `dot` option, which was always `true`, and the unused `Glob` type. With that, `micromatch` and `@types/micromatch` are no longer dependencies of `@expo/metro-file-map`. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. # Test Plan New unit test for `isIncluded`, ported from upstream. `pnpm test`, `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`. The CLI E2E suite exercises the watchers through the injected file map. # Checklist - [x] I added a changeset and followed [this short guide](https://github.com/expo/expo/blob/main/CONTRIBUTING.md#-before-submitting) - [ ] This diff will work correctly for `npx expo prebuild` & EAS Build (eg: updated a module plugin). - [ ] Conforms with the [Documentation Writing Style Guide](https://github.com/expo/expo/blob/main/guides/Expo%20Documentation%20Writing%20Style%20Guide.md)
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Cherry-pick of #51093 onto `sdk-58`. It ports react/metro#2000 and its follow-up react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How The same change as on `main`. The watchers' `globs` option is replaced by `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, as the `**/*.<ext>` globs did with `dot: true`. This keeps `.env` matching the `env` extension that `@expo/metro-config` adds to `watcher.additionalExts`, which `path.extname` would miss. The watchers' `dot` option, which was always `true`, and the unused `Glob` type are removed, and with them the `micromatch` and `@types/micromatch` dependencies. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. The merged commit from #51093 (52acc2c) cherry-picked cleanly. The `.changeset` file is replaced by a `CHANGELOG.md` entry, because `sdk-58` does not use changesets. # Test Plan New unit test for `isIncluded`, ported from upstream and extended with dotfile and multi-part extension cases. A one-off script checked `isIncluded` against `micromatch.some(path, globs, {dot: true})` on 21 edge cases (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, …) with no mismatches. On this branch, `pnpm test` (725 tests), `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`, and `pnpm install --frozen-lockfile` accepts the lockfile. The CLI E2E suite exercises the watchers through the injected file map, including `.env` reloads in `hmr-env-vars.test.ts`. # Checklist - [x] I added a `CHANGELOG.md` entry. - [ ] Docs: not applicable. (cherry picked from commit 52acc2c)
This was referenced Oct 5, 2026
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Cherry-pick of #51093 onto `sdk-58`. It ports react/metro#2000 and its follow-up react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How The same change as on `main`. The watchers' `globs` option is replaced by `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, as the `**/*.<ext>` globs did with `dot: true`. This keeps `.env` matching the `env` extension that `@expo/metro-config` adds to `watcher.additionalExts`, which `path.extname` would miss. The watchers' `dot` option, which was always `true`, and the unused `Glob` type are removed, and with them the `micromatch` and `@types/micromatch` dependencies. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. The merged commit from #51093 (52acc2c) cherry-picked cleanly. The `.changeset` file is replaced by a `CHANGELOG.md` entry, because `sdk-58` does not use changesets. # Test Plan New unit test for `isIncluded`, ported from upstream and extended with dotfile and multi-part extension cases. A one-off script checked `isIncluded` against `micromatch.some(path, globs, {dot: true})` on 21 edge cases (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, …) with no mismatches. On this branch, `pnpm test` (725 tests), `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`, and `pnpm install --frozen-lockfile` accepts the lockfile. The CLI E2E suite exercises the watchers through the injected file map, including `.env` reloads in `hmr-env-vars.test.ts`. # Checklist - [x] I added a `CHANGELOG.md` entry. - [ ] Docs: not applicable. (cherry picked from commit 52acc2c)
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Cherry-pick of #51093 onto `sdk-58`. It ports react/metro#2000 and its follow-up react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How The same change as on `main`. The watchers' `globs` option is replaced by `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, as the `**/*.<ext>` globs did with `dot: true`. This keeps `.env` matching the `env` extension that `@expo/metro-config` adds to `watcher.additionalExts`, which `path.extname` would miss. The watchers' `dot` option, which was always `true`, and the unused `Glob` type are removed, and with them the `micromatch` and `@types/micromatch` dependencies. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. The merged commit from #51093 (52acc2c) cherry-picked cleanly. The `.changeset` file is replaced by a `CHANGELOG.md` entry, because `sdk-58` does not use changesets. # Test Plan New unit test for `isIncluded`, ported from upstream and extended with dotfile and multi-part extension cases. A one-off script checked `isIncluded` against `micromatch.some(path, globs, {dot: true})` on 21 edge cases (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, …) with no mismatches. On this branch, `pnpm test` (725 tests), `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`, and `pnpm install --frozen-lockfile` accepts the lockfile. The CLI E2E suite exercises the watchers through the injected file map, including `.env` reloads in `hmr-env-vars.test.ts`. # Checklist - [x] I added a `CHANGELOG.md` entry. - [ ] Docs: not applicable. (cherry picked from commit 52acc2c)
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Cherry-pick of #51093 onto `sdk-57`. It ports react/metro#2000 and its follow-up react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How The same change as on `main`. The watchers' `globs` option is replaced by `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, as the `**/*.<ext>` globs did with `dot: true`. This keeps `.env` matching the `env` extension that `@expo/metro-config` adds to `watcher.additionalExts`, which `path.extname` would miss. The watchers' `dot` option, which was always `true`, and the unused `Glob` type are removed, and with them the `micromatch` and `@types/micromatch` dependencies. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. The merged commit from #51093 (52acc2c) cherry-picked cleanly. The `.changeset` file is replaced by a `CHANGELOG.md` entry, because `sdk-57` does not use changesets. # Test Plan New unit test for `isIncluded`, ported from upstream and extended with dotfile and multi-part extension cases. A one-off script checked `isIncluded` against `micromatch.some(path, globs, {dot: true})` on 21 edge cases (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, …) with no mismatches. On this branch, `pnpm test` (725 tests), `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`, and `pnpm install --frozen-lockfile` accepts the lockfile. The CLI E2E suite exercises the watchers through the injected file map, including `.env` reloads in `hmr-env-vars.test.ts`. # Checklist - [x] I added a `CHANGELOG.md` entry. - [ ] Docs: not applicable. (cherry picked from commit 52acc2c)
robhogan
added a commit
to expo/expo
that referenced
this pull request
Oct 5, 2026
# Why Cherry-pick of #51093 onto `sdk-56`. It ports react/metro#2000 and its follow-up react/metro#2024 to `@expo/metro-file-map`. `micromatch` depends on `braces`, which has a CVE ([GHSA-vfj7-8cjw-p6xm](GHSA-vfj7-8cjw-p6xm)). The fork only uses `micromatch` to filter watcher change events, against globs it builds itself from `extensions`, `package.json` and the health check file prefix. None of them are configurable, so all it ever checks is an extension, a file name or a prefix. # How The same change as on `main`. The watchers' `globs` option is replaced by `included`, a set of `extensions`, `basenames` and `basenamePrefixes` checked with `Set` lookups and `startsWith`. A file matches an extension when its basename ends with `.` followed by that extension, as the `**/*.<ext>` globs did with `dot: true`. This keeps `.env` matching the `env` extension that `@expo/metro-config` adds to `watcher.additionalExts`, which `path.extname` would miss. The watchers' `dot` option, which was always `true`, and the unused `Glob` type are removed, and with them the `micromatch` and `@types/micromatch` dependencies. One difference from upstream: the fork's `healthCheckFilePrefix` is nullable, so a null prefix now adds no prefix match rather than a literal `**/null*` glob. The cherry-pick of the merged commit from #51093 (52acc2c) had one conflict. `FallbackWatcher.test.ts` doesn't exist on `sdk-56`, and the pick only updated the watcher options it passes, so I resolved it by keeping the file deleted. The `.changeset` file is replaced by a `CHANGELOG.md` entry, because `sdk-56` does not use changesets. # Test Plan New unit test for `isIncluded`, ported from upstream and extended with dotfile and multi-part extension cases. A one-off script checked `isIncluded` against `micromatch.some(path, globs, {dot: true})` on 21 edge cases (`.env`, `.env.local`, `.envrc`, `src/.js`, `a.d.ts`, `a.js.map`, `a..js`, …) with no mismatches. On this branch, `pnpm test` (720 tests), `pnpm typecheck` and `pnpm lint` pass in `packages/@expo/metro-file-map`, and `pnpm install --frozen-lockfile` with pnpm 10 (as CI uses on this branch) accepts the lockfile. The CLI E2E suite exercises the watchers through the injected file map, including `.env` reloads in `hmr-env-vars.test.ts`. # Checklist - [x] I added a `CHANGELOG.md` entry. - [ ] Docs: not applicable. (cherry picked from commit 52acc2c)
This was referenced Oct 5, 2026
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.
#2000 replaced the watchers' globs with
included, comparing extensions usingpath.extname. That isn't quite what the**/*.<ext>globs did withdot: true-path.extname('.env')is'', so.envno longer matches anenvextension, and a multi-part extension liked.tsnever matches.This was picked up by Expo CI, which adds
envtowatcher.additionalExtsso that editing.envtriggers a reload.This matches an extension when the basename ends with
.followed by that extension, after any dot, which is what the globs matched.Changelog: Internal (#2000 is unreleased)
Test plan:
Extended
common-test.jswith dotfile and multi-part extension cases.Compared against
micromatch.some(path, globs, {dot: true})with the globs Metro used to build, on 21 edge-case paths (.env,.env.local,.envrc,src/.js,a.d.ts,a.js.map,a..js, ...), with no mismatches.Found by Expo's
hmr-env-varsE2E test failing on the port of #2000 to Expo's file map, that PR now includes this fix and CI passes: expo/expo#51093