Repository navigation
fix(metro): skip the generated uniwind.css when tracking imported CSS - #720
dlebedynskyi wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Filter and dependency collection packages/uniwind/src/bundler/adapters/metro/transformer.ts, packages/uniwind/tests/native/bundler/transformer.test.ts, CONTEXT.md |
The transformer excludes the generated artifact when its resolved path matches the artifact path. Tests check real and linked paths and confirm other imported local stylesheets remain in the collected dependencies. |
Priority:
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix
Possibly related PRs
- uni-stack/uniwind#676: Adds the imported-stylesheet dependency path that this change filters.
- uni-stack/uniwind#721: Changes Metro traversal behavior for CSS entries marked
css.skipCache, which is related to CSS entry rebuilds.
Suggested reviewers: brentlok, fendyk
Merge Risk: 
Minimal · up to 27c35
-
No actionable merge-blocking risk remains from this change.
Pre-merge checks: 
5
-
Full details: Docstring Coverage
-
Explanation
No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 2 files. (1 skipped: 1 unsupported.)
-
Finishing Touches
-
🧪 Generate unit tests (beta)
-
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
6d9d064 to
db8ee0c
Compare
Since uni-stack#676, development native entries require every stylesheet Tailwind reports that isn't under node_modules. When uniwind is linked (a workspace package, `npm link`, a `file:` install), Tailwind resolves `@import 'uniwind'` to the package's uniwind.css by its real path, outside node_modules. The entry then requires the artifact that its own transform rewrites. Every write changes a module in Metro's graph and re-runs the uncached entry transform. A single server rebuilds the entry once more at startup, and two Metro servers with different theme lists rewrite the artifact for each other indefinitely. Leave out the stylesheet whose real path is the generated artifact's. Local stylesheets and linked workspace stylesheets are still required.
db8ee0c to
27c3511
Compare
[Medium impact] The PR appears safe to merge. SummaryNative Metro development builds now exclude the generated
|
| // Local stylesheets a development entry requires, so editing one re-runs its transform. When uniwind is linked | ||
| // (a workspace package, `npm link`), `@import 'uniwind'` resolves to the generated artifact outside node_modules. | ||
| // Requiring it would rebuild the entry after each write, and Metro servers with different themes after each other's. |
There was a problem hiding this comment.
It could be simplified
| // Local stylesheets a development entry requires, so editing one re-runs its transform. When uniwind is linked | |
| // (a workspace package, `npm link`), `@import 'uniwind'` resolves to the generated artifact outside node_modules. | |
| // Requiring it would rebuild the entry after each write, and Metro servers with different themes after each other's. | |
| // Exclude the generated artifact to prevent rebuild loops when uniwind is linked. |
I ran into this in a monorepo where uniwind is a workspace package. After #676, two apps' Metro dev servers running at the same time kept rebuilding each other, because each entry now watched the generated
uniwind.cssthat the other server kept rewriting. Clode did the most of the work bellow.This follows up #676. When uniwind is linked instead of installed, the native development entry requires
uniwind.css. That's the file the entry's own transform rewrites. Linked setups include a workspace package (like the examples in this repo),npm link, or afile:dependency. If two Metro servers with different theme lists run at once, each one's writes rebuild the other, and it never stops.On
main(9fc9b40), I added anhmr-tokens.cssimport toapps/expo-example/global.cssand fetched the iOS dev bundle. These are the stylesheets the CSS entry module depends on:global.css -> ["hmr-tokens.css", "../../packages/uniwind/uniwind.css"]apps/barebehaves the same way:src/global.css -> ["src/hmr-tokens.css", "../../packages/uniwind/uniwind.css"].Next I ran
apps/expo-example(light, dark, premium) alongside a copy of it with one extra theme (extraThemes: ['premium', 'ocean']). Each ranexpo startfrom its own directory, with an HMR client registered for its iOS bundle. I counted the HMR updates that carried modules and the writes topackages/uniwind/uniwind.css:uniwind.csswritesThis keeps going until one of the servers stops. Each rebuild runs the Tailwind compile for the entry again.
A single server pays once. On a fresh install the shipped artifact doesn't match the app's themes (
expo-exampleaddspremium), so the first transform rewrites it. When the HMR client connects, Metro handles that change and transforms the entry a second time.Cause
#676 requires every stylesheet Tailwind reports through
onDependencythat ends in.cssand isn't undernode_modules. Tailwind's resolver follows symlinks. So whennode_modules/uniwindis a link,@import 'uniwind'is reported by its real path,packages/uniwind/uniwind.css, and that passes the filter. It's the same filegenerateArtifacts(cssArtifactPath)writes at the start of the transform.Once the artifact is a module in the graph, Metro handles every write to it as a change, and the uncached entry gets transformed again, which regenerates the artifact. With one theme list, the second write has identical content and is skipped. With two servers, each writes its own themes, which the other sees as a change.
Fix
isImportedStylesheetkeeps the existing rules and also drops the stylesheet whose real path matches the generated artifact's. Both sides are resolved, so the check still works when the artifact path itself goes through a link. Local stylesheets and those of linked workspace packages are still required, so token edits still hot reload. I also added a line about this toCONTEXT.md.Testing
tests/native/bundler/transformer.test.tssets up a linked layout in a temporary directory:node_modules/uniwindandnode_modules/brandlink intopackages/, next to a regularnode_modules/theme. It compiles an entry that imports all three plus a localtokens.csswith Tailwind, then checks which reported stylesheets the entry keeps (tokens.cssandbrand.css). It covers the artifact path given as a real path and as a path through the link. With the old filter, both cases fail because they keeppackages/uniwind/uniwind.css. A plain string comparison passes the real-path case but fails the linked one.hmr-tokens.css.bun run test(native 205, web 48, e2e 9, types). I also exportedapps/expo-examplefor iOS, Android and web, builtapps/vite-example, and bundledapps/bare.For the two-server run I used a second Expo app, not
apps/bare. The bare app's React Native CLI runs its own Metro 0.84, while uniwind patches the root Metro 0.85, so Metro doesn't re-run the bare entry on file changes. Withapps/expo-exampleandapps/baretogether, the artifact was written three times at startup, each server rebuilt once, and then it stopped. The bare entry still requires the artifact.Who's affected
This affects native development builds with Metro where uniwind resolves outside
node_modules:workspace:*, as in this repo)npm link, or afile:/link:dependency that's installed as a symlinkRegular installs aren't affected because Tailwind reports a path under
node_modules, and that includes pnpm'snode_modules/.pnpm. Production builds and web don't add these requires, so they aren't affected either.The endless rebuilds need two or more Metro servers that share one uniwind copy and use different theme lists, for example two apps in the same monorepo. A single server transforms its entry one extra time at startup whenever the installed artifact doesn't match its themes.
Summary by CodeRabbit
uniwind.cssartifact among imported stylesheet dependencies, including when it is referenced through a linked path.