Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement stylex.defineConsts #724

Open
nmn opened this issue Oct 9, 2024 · 0 comments
Open

Implement stylex.defineConsts #724

nmn opened this issue Oct 9, 2024 · 0 comments
Labels
enhancement New feature or request question Further information is requested

Comments

@nmn
Copy link
Contributor

nmn commented Oct 9, 2024

Depends on #517


Implement a new stylex.defineConsts API that works exactly like stylex.defineVars with two differences:

  1. It is impossible to create themes for these sets of constants.
  2. It is possible to define types of values that are not supported within defineVars.
    • Initially, we would want to support shared media queries.

How this will enable sharable media queries:

export const media = stylex.defineConsts({
  sm: stylex.types.media('(min-width: 768px)'),
  md: stylex.types.media('(min-width: 1024px)'),
  lg: stylex.types.media('(min-width: 1600px)'),
});

These can then be used like this:

const styles = stylex.create({
  base: {
    fontSize: {
      default: 16,
      [`@media ${viewports.sm}`]: 18, 
      [`@media ${viewports.md}`]: 20, 
      [`@media ${viewports.lg}`]: 24, 
      '@media (min-width: 1024px)': 20, 
    },
  },

Behind the scenes, shared media queries should compile to the @custom-media proposal which
can then be compiled away in the CSS post-processing step. (probably by lightningcss)


There are two major challenges to consider with this feature:

Avoiding conflicts

Once we introduce shared media queries, we will no longer be able to detect overlapping media queries within a value statically. This is a solvable problem with combination of compilation-time and post-processing transformations.

Give the examples above, assume the initial constants are compiled to the following CSS:

@custom-media --vw-sm (min-width: 768px);
@custom-media --vw-md (min-width: 1024px);
@custom-media --vw-lg (min-width: 1600px);

However, in order to resolve any conflicts, the styles above would be transformed into:

const styles = stylex.create({
  base: {
    fontSize: {
      default: 16,
      '@media (--vw-sm) and not (--vw-md) and not (--vw-lg) and not (min-width: 1024px)': 18, 
      '@media (--vw-md) and not (--vw-lg) and not (min-width: 1024px)': 20, 
      '@media (--vw-lg) and not (min-width: 1024px)': 24, 
      '@media (min-width: 1024px)': 20, 
    },
  },

These styles would then be simplified after the final CSS file is generated.

Dealing with duplicate CSS rules

Since StyleX cannot know the value of a shared media query at compile time, the generated className will be different from the hash had the literal value been used instead.

Therefore, there is no way to support shareable constants (media queries or otherwise) without
duplicating some CSS rules.

However, our CSS post-processing should be able to find and combine duplicate rules and minimize the performance impact of this duplication.

.hash1, .hash2 { <rule generated twice with different classNames> }

The assumption here is that if you define shared constants, you should be expected to use them consistently across the codebase. We could also implement a lint rule to enforce this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request question Further information is requested
Projects
None yet
Development

No branches or pull requests

1 participant