Skip to content

Conversation

@Prakshal-Jain
Copy link
Contributor

@Prakshal-Jain Prakshal-Jain commented Oct 27, 2025

What changed / motivation?

Introducing a new ESLint rule stylex-validate-media-queries that validates media query syntax in StyleX declarations. The motivation is to provide early feedback to developers about invalid media queries during development and flag when media query order cannot be enforced.

Key Changes:

  • Added stylex-validate-media-queries rule that checks media query syntax in stylex.create() and stylex.createTheme() calls
  • Implemented a softValidation option in the babel plugin that allows media query validation to be handled by ESLint instead of failing at build time
  • The rule validates:
    • Media query syntax and structure
    • Valid media types (screen, print, all, etc.)
    • Valid media features (width, height, orientation, etc.)
    • Proper use of logical operators (and, or, not)
    • Range syntax and value formats
  • Developer Experience: Provides clear, actionable error messages with specific guidance on what's wrong and how to fix it

Linked PR/Issues

Fixes #1200

Tests

  • Added test suite covering valid and invalid media query patterns
  • Tests include edge cases like nested conditions, range syntax, and various media features
  • All existing tests continue to pass

Configuration

The ESLint rule can be enabled in .eslintrc:

{
  "rules": {
    "@stylexjs/stylex-validate-media-queries": "error"
  }
}

The babel plugin's soft validation mode can be enabled via:

{
  plugins: [
    ['@stylexjs/babel-plugin', { 
      softValidation: ['mediaQueries'] 
    }]
  ]
}

Breaking Changes

None - this is an opt-in feature that doesn't affect existing functionality.

Pre-flight checklist

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Oct 27, 2025
let lastMediaQueryWinsTransform = null;
try {
// $FlowFixMe Dynamic import for style-value-parser since it might not be available in all environments
const styleValueParser = require('style-value-parser');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mellyeliu Not sure if the import statement is safe here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm why cjs here? let's use esm import instead

@github-actions
Copy link

github-actions bot commented Oct 27, 2025

workflow: benchmarks/perf

Comparison of performance test results, measured in operations per second. Larger is better.

benchmarks@0.16.2 compare
node ./compare.js /tmp/tmp.lUTBpjgZaP /tmp/tmp.GOin9WNhhx

Results Base Patch Ratio
babel-plugin: stylex.create
· basic create 636 645 1.01 +
· complex create 201 193 0.96 -
babel-plugin: stylex.createTheme
· basic themes 460 454 0.99 -
· complex themes 43 43 1.00

@github-actions
Copy link

github-actions bot commented Oct 27, 2025

workflow: benchmarks/size

Comparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.

benchmarks@0.16.2 compare
node ./compare.js /tmp/tmp.8nDJGbZudP /tmp/tmp.X5kQPrbHWz

Results Base Patch Ratio
@stylexjs/stylex/lib/cjs/stylex.js
· compressed 1,282 1,282 1.00
· minified 4,025 4,025 1.00
@stylexjs/stylex/lib/cjs/inject.js
· compressed 1,223 1,223 1.00
· minified 3,216 3,216 1.00
benchmarks/size/.build/bundle.js
· compressed 496,650 496,650 1.00
· minified 4,847,840 4,847,840 1.00
benchmarks/size/.build/stylex.css
· compressed 99,853 99,853 1.00
· minified 747,541 747,541 1.00

Copy link
Member

@mellyeliu mellyeliu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall. Couple of nits and suggestions to start out

type: 'problem',
docs: {
description:
'Warn when media query syntax may not be correctly ordered due to parser limitations',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
'Warn when media query syntax may not be correctly ordered due to parser limitations',
'Warn when media query syntax order is not properly enforced due to invalid media query syntax or parser limitations',

}

if (prop.computed) {
continue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is fine for now, we'll eventually need to think of how to handle defineConsts computed keys here though

`StyleX: ${messages.INVALID_MEDIA_QUERY_SYNTAX}\n` +
'Media query order will not be respected. ' +
'This could be due to invalid media query syntax or unsupported edge cases in style-value-parser.\n' +
`Error: ${error.message || error}`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we validate that this error message contains the erroring media query?

throw new Error(messages.INVALID_MEDIA_QUERY_SYNTAX);
if (options.softMediaQueryValidation) {
console.warn(
`StyleX: ${messages.INVALID_MEDIA_QUERY_SYNTAX}\n` +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably don't need to "StyleX: " prefix here

z.logAndDefault(
z.boolean(),
options.softMediaQueryValidation ?? false,
false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make this true for now

const styles = stylex.create({
main: {
color: {
'@media (min-width: 768px)': 'blue',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we require a default with every contextual style:

Suggested change
'@media (min-width: 768px)': 'blue',
default: 'yellow',
'@media (min-width: 768px)': 'blue',

`,
errors: [
{
message: /Media query order may not be respected/,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why the rest of the error is not showing up here? Seems out of sync with the rule file itself

import sortKeys from './stylex-sort-keys';
import validShorthands from './stylex-valid-shorthands';
import validStyles from './stylex-valid-styles';
import validateMediaQueries from './stylex-validate-media-queries';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's call this transform-media-queries or something similar

"micromatch": "^4.0.5",
"postcss-value-parser": "^4.2.0"
"postcss-value-parser": "^4.2.0",
"style-value-parser": "*"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe style-value-parser is already added to workspaces at the root level so it's inlined instead, as it's a private package, see: https://github.com/facebook/stylex/blob/main/package.json#L20

@mellyeliu mellyeliu changed the title Add media queries validation eslint rule with soft validation support [eslint-plugin] Add transform-media-query rule and soft validation config Oct 27, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[style-value-parser] implement "soft" validation of queries

3 participants