Skip to content

feat(metro): surface compiler warnings during a build - #430

Open
YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:feat/metro-compiler-warnings
Open

YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:feat/metro-compiler-warnings

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Aug 15, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Closes #424.

On main, compile(css).warnings() collects everything the compiler could not translate, but src/metro/metro-transformer.ts calls .stylesheet() and discards the rest of the compile result. So a dropped float or z-index: auto is silent in every build.

lightningcss also warns about input it cannot parse, such as an unknown at-rule or an unrecognised pseudo-element. lightningcss passes the rule through, the visitor finds nothing in it, and the rule disappears. The compiler never reads those warnings.

Solution

  • The transformer hands .warnings() to reportCompilerWarnings, which prints one block per stylesheet:

    react-native-css: src/global.css - 3 declarations dropped, no React Native equivalent
      properties: columns, float
      values: z-index: auto
    

    A file's block prints when its set of warnings changes, so an incremental rebuild that changes nothing about them stays quiet. Warnings never fail a build.

  • A warnings option on withReactNativeCSS sets how much is printed. Issue compile().warnings() is unreachable from a real build: 50 addWarning call sites, no Metro consumer #424 offered three shapes, and this PR implements option 1 with option 2's escape hatch:

    • "summary" (the default) caps each channel at ten entries;
    • "verbose" lists everything;
    • "none" prints nothing.

    An opt-in default would leave the channel unseen by anyone who doesn't read the docs. If you'd rather it defaulted to "none", that's a one-word change.

  • lightningcss's parse warnings from the first pass go to a new syntax channel. It is kept apart from what React Native cannot express, because the fix for it is in the author's stylesheet. This package's own @nativeMapping is not reported.

  • The README documents the option.

Tests

  • src/__tests__/metro/warnings.test.ts builds its fixtures from real compile() results and covers:
    • the formatting;
    • the caps;
    • the syntax clause;
    • re-printing only on a change;
    • a file that stops warning and warns again;
    • paths inside and outside the project root.
  • src/__tests__/metro/metro-transformer.test.ts drives the transformer with a stand-in for Expo's transform worker, and checks that the level and the file reach the report. It also checks that web and non-CSS files never print.
  • src/__tests__/compiler/warnings.test.ts covers the syntax channel: an unknown at-rule and an unrecognised pseudo-element, each dropping its rule; a correctly spelled control; this package's own at-rule; and a repeated mistake.
  • On main, 6 of the 14 cases in the files that load there fail; warnings.test.ts exercises the new module. Each of 17 mutations fails its own cases.
  • yarn example expo export --platform android prints the block for the example's global.css: 42 declarations from Tailwind's preflight.

Verification

On Windows with Node 26:

  • yarn lint clean
  • yarn typecheck clean
  • yarn test --coverage: every failure also fails on main on this machine (the four babel cases)
  • yarn build clean
  • yarn example expo export --platform web exported

Merge order

It shares lines with #411 (README.md), #460 (compiler/compiler.ts); whichever lands second rebases.

It also shares lines with #428 (README.md); whichever lands second rebases.

Base

Re-written on main (a5002c5), and no longer stacked on #390: nothing here depends on its babel changes. main refuses @react-native blocks outright, so the filter for this package's own at-rules now covers only @nativeMapping.

@YevheniiKotyrlo

YevheniiKotyrlo commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor Author

No device frame

The change is terminal output, and the description shows the block a build prints.

YevheniiKotyrlo added a commit to YevheniiKotyrlo/react-native-css that referenced this pull request Sep 22, 2026
This branch's first commit added a local logWarnings to the metro
transformer, using picocolors directly. PR nativewind#430 adds the same feature to
the same file through an extracted ./warnings module, so the two
conflict and whichever lands second rewrites the other.

Nothing here needs it: the compiler suites assert compiled.warnings()
directly, and all 277 tests across the three border suites pass without
it. It also left this branch changing a metro source with no metro test,
which is the only reason that plane looked uncovered.
The compiler records every declaration it could not translate, but nothing
read compile().warnings() during a build, so a dropped float or
z-index: auto was silent. The Metro transformer now prints one block per CSS
file: capped in summary mode, listed in full in verbose mode, and printed
again only when the file's warnings change. The warnings option sets the
level, and none silences it.

lightningcss also warns about input it cannot parse, such as an unknown
at-rule or pseudo-element, whose rule then disappears. Those warnings reach a
new syntax channel, kept apart from what React Native cannot express; this
package's own @nativeMapping is not reported.

This branch has not been deployed

No deployments
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.

compile().warnings() is unreachable from a real build: 50 addWarning call sites, no Metro consumer

1 participant