Skip to content

Feature: support cross-file transform inputs with cache and watch invalidation #1902

Open

Description

@mfkrause

Metro has no supported way for a transform to state that its output depends on some other source file or graph-derived value.

For example:

// Card.tsx
export const Card = ({children}) => <View>{children}</View>;

// Screen.tsx
export const Screen = () => (
 <Card>
   <Text>Hello</Text>
 </Card>
);

Say that we wanted to transform Screen.tsx, but only if Card.tsx wraps its children under a View. If Card later changes its wrapper component to something else, we need to undo this transformation.

Currently, this is not possible. If Card.tsx changes, Metro transforms Card.tsx, but not the unchanged Screen.tsx. Instead, it returns the old, transformed Screen.tsx from its cache because its cache key does not include Card.tsx.

I see two possible designs:

  • A transform-dependency API that records additional file paths or input hashes.
  • A graph-level analysis hook that runs after dependency discovery but before final transforms, and provides immutable per-file data to workers.

Related: #918, #1488, and #1605.

Activity

  1. robhogan commented on Sep 4, 2026

    @robhogan
    Collaborator

    I can confirm that's true :) If this is a feature request, do you have a use case in mind?

    Multi-module transforms are against the grain of Metro's design, but we're working on a cache-safe virtual module implementation at the moment that can read multiple files at the resolver phase, which I believe should fill the gap. The more concrete use cases we know about, the more chance we get that design right.

  2. mfkrause commented on Sep 4, 2026

    @mfkrause
    ContributorAuthor

    Sorry if that was unclear, it is a feature request, yes! :)

    To be fair, the use case is quite niche: https://github.com/kuatsu/react-native-boost
    tldr; We replace JS wrapper components like "View" and "Text" with their native host components through a Babel plugin where safe. The "where safe" part requires the plugin to know what its ancestors are, since that depends on whether or not the component requires specific context providers (which normally the wrapper components would provide). With the Babel plugin, we were unable to check this across file boundaries. I'm currently migrating the library to a Metro config adapter (for different reasons mainly). I had the hope that I could utilize its module graph to do those checks beyond file boundaries, but then hit this limitation.

    For what it's worth, I found two more popular libraries in the ecosystem that have hit the same wall or a similar wall, namely Uniwind and Tamagui. Tamagui seems to simply accept this stale cache risk, while Uniwind juggles internal Metro APIs (something I've settled on for now as well).

    I saw the virtual module RFC, but I don't think it would fill my specific gap. It seems to deal with the worker and graph plumbing, but doesn't seem to address the cache part. It's late here though, so I may be missing something.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions