facebook / facebook/stylex

Implement `stylex.defineConsts`

Open
#724 0 comments 24 reactions 1 assignee Claimed by @mellyeliu View on GitHub
enhancement question
Dominant language
JavaScript
Stars
10.3k
Forks
481
Avg merge
3d 8h
Merged PRs (30d)
13

Description

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:

```ts
export const viewports = 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:

```ts
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:

```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:

```ts
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.

```css
.hash1, .hash2 { }
```

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?

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.