Naman Goel - StyleX

Durée: 64m33s

Date de sortie: 17/06/2024

This week we have Naman Goel, the technical lead of StyleX. Stylex is a CSS-in-JS used by Facebook to build the styling of Facebook's products. We talk about the history of StyleX, how it works, and how it's better than other CSS-in-JS solutions. We also talk about how flow is better than TypeScript and why you should be using Swift over Rust.

Episode sponsored By Clerk (https://clerk.com)

Become a paid subscriber our patreon, spotify, or apple podcasts for the full episode.

Le problème est que, à la scale, quand vous avez des milliers de personnes en travaillant sur le UI et le CSS,
certains personnes vont faire des règles.
Elles vont faire des sélecteurs complexes, des sélecteurs descendants, des styles globales, etc.
Nous avons des problèmes de wars de spécificité entre les styles,
où vous ne pouvez pas le faire parce que les styles résolvent différemment
selon comment les utilisateurs naviguent sur Facebook.
C'est ce que nous essayons de se solider.
Merci d'avoir regardé notre vidéo.
Clément, bonjour.
Vous pouvez riler avec le Logo après,

Salut, bienvenue dans le speakers de DevTools FM.

et d'un coup des gens qui 1975.
Je travaille en meta, j'ai travaillé en meta pendant 7 ans.
J'ai commencé à travailler sur Stylix 5 ans plus tard,
et j'ai commencé à travailler sur un nouveau site, comme rewriteoffaitbook.com
qui, si quelqu'un utilise le web, vous aurez probablement vu ça.
On a changé le tout le looks et tout.
J'étais originalement en Indie, j'ai travaillé en Espagne pour un an,
ça pourrait être une chose intéressante.
Et oui, c'est moi.
C'est cool de vous parler de ça.
Stylix a une longue histoire.
Comment vous ressentez de changer,
depuis que le projet a commencé,
à ce moment où nous sommes aujourd'hui ?
Bien sûr.
Stylix a été créé pour le Facebook.com,
originalement.
C'était environ 5 ans,
et le premier qui a travaillé sur ça
était Sebastian McKenzie,
l'autor de Babel.
Il a pris une semaine, il a pris quelque chose ensemble,
et c'était très bas de la paix.
Le premier version n'a pas eu un compiler,
le premier version était une réplique,
une implementation,
et je pense qu'il a pris 3 jours,
c'était avant que je rejoignais le team,
je n'étais pas complètement sûr sur la timeline,
mais ils ont très rapidement réalisé que ce n'était pas un peu flippant.
C'était trop bas pour le Facebook,
et ils ont impliqué un compiler,
et c'était juste le minimum de compiler que vous avez.
Sebastian était en train de laisser la compagnie,
comme Rome,
Rome Tools,
qui n'existe plus,
mais il était en train de laisser la compagnie.
J'ai jointé le team,
c'était le team des systèmes de design,
comme vous le parliez,
on l'a appelé le team des compagnies,
on a construit tous les compagnies
de la courte-up.
Et donc,
le manière dont j'ai commencé à travailler sur ça,
n'était pas comme,
je suis acheté cette pièce d'infrastructure,
c'était plus comme,
je suis sur un team qui construit des compagnies,
et on a besoin de style,
comme c'est ce qu'on est construit,
et j'ai commencé à hacker sur ça,
pour faire mon besoin.
On a besoin de features pour construire des compagnies.
Et donc,
depuis le jour 1,
Stylex a toujours évolué,
et on a été informés par nos besoins,
comme des compagnies d'alimentation,
et aussi,
les teams productifs qui ont utilisé nos compagnies
ont voulu l'utiliser.
C'est comme ça,
ça s'est évolué,
et à un point,
il y avait une petite période de temps,
l'année dernière,
quand j'étais allé en source,
en focusant entièrement sur Stylex,
et j'ai bougé les teams,
et puis j'ai bougé au fond de la team des compagnies,
parce que très vite,
je réalise que
ça m'a aidé,
en n'avoir pas de directe interaction
avec les teams productifs,
et les compagnies de construire,
ça fait un certain nombre de connaissances
de ce qui serait la meilleure décision de design.
Vous venez de commencer à faire des décisions

qui ne peuvent pas être réalisées,
et donc,
dans quelques mois,
je me suis dit que je devais
prendre des temps à construire,
en travaillant sur Stylex, 100%.
Quand vous étiez initialement
exploré des solutions,
avez-vous essayé des modules CSS
ou d'autres choses?
Qu'est-ce que Stylex a fait
que le library extra s'est nécessité?
C'est vrai.
Alors,
nous allons commencer par où nous sommes.
Nous avons utilisé quelque chose
qui ressemble à la module CSS.
C'est un très custom
que vous avez obtenu,
et c'est juste
des spaces de la classe.
Vous vous mettez un slash
dans la classe,
et le bar se règle.
C'est tout de même
ce que l'infowords
a fait,
mais toutes les mêmes
ramifications de modules CSS
sont lesquelles nous sommes.
Et ce que nous avons réveillé
était
des raisons historiques,
et des raisons pour les modules CSS.
Nous avons
des milliers de components
qui sont sur Facebook.com,
sur notre page.
Et
je ne veux pas vous donner
une telle quantité,
mais c'était
quelque part entre 15 et 45 megabytes
de CSS
qui étaient bloqués
pour l'utilisateur avarais
sur une page de la seule page.
Et c'était parce que
et ce n'était pas parce
que nous étions juste bloqués
tout à l'arrivée.
C'était
le correctement de
ce component bloqués,
donc nous l'avons bloqué pour ce component.
C'était le bon moment
de voir ce que nous étions

Mais ce n'était pas
le plus grand problème.
Le plus grand problème
était que
ce serait plus
un peu de raison historique
dans les modules CSS
avec des layers de CSS
et des choses qui pourraient être
plus belles.
Mais vraiment,
le problème est que
à la scale,
quand vous avez des milliers
de gens qui travaillent
sur le UI et le CSS,
certains gens
vont faire des règles.
Ils vont faire des sélecteurs complexes,
ils vont faire des sélecteurs
dans des styles globales
et des choses comme ça.
Et donc, il y avait assez
de ce que nous avons
des problèmes de
les wars de spécificité
entre les styles
où vous ne pouvez pas le fixer
parce que les styles
se réservent différemment
selon comment les gens
naviguèrent sur Facebook
parce que
que si vous naviguez
à la fin,
vous êtes bloqué à la fin
et que ça a le plus
spécificité.
C'était un grand problème.
C'est ce que nous étions
essayant de se solider.
Et donc,
le premier verre
de style,
comme ça,
c'était de la journée
qu'on savait que c'était
ce que nous avons besoin,
c'était que ça a toujours
généré des styles atomiques,
qui sont les classes atomiques.
Et la raison pour ça
était que
même si
il y avait des sélecteurs
de trade-offs,
il y avait beaucoup de tests
recentes
qui ont été faits
aussi sur
les sélecteurs de trade-offs.
Mais les sélecteurs de trade-offs
sont basically,
si vous avez
beaucoup de classes
de l'élément,
il y a un petit hit
que vous avez fait.
Donc,
quand le browser
s'est résolué de styles,
si vous avez
10 classes de l'élément
vers juste un classes
de l'élément,
les 10 classes
sont un peu plus serelles,
comme vous pouvez le measure.
Mais,
ce n'était pas
plus que le nombre
de CSS que vous avez
élevé.
Et pour vous donner
des proches,
nous
sommes
dans l'arrière
de 200, 300 kilobytes.
Donc, nous avons
depuis 15, 30, 45
megabytes
à
200, 300 kilobytes.
Et c'est
tout de
Facebook.
Donc,
vous pouvez continuer de naviguer
et nous ne vous en rajouter
plus pour la plupart.
Il y a
une main-d'oeuvre
d'exception
de très rares pages,
mais
la majorité de Facebook
juste travaille
sur un single
CSS bundle.
Et,
oui, nous sommes
dans le cadre de ça.
Nous avons changé
beaucoup de détails
sur comment
les choses sont générées.
Il y a
beaucoup de questions
de, hey,
nous en générer.
Donc,
internement, nous
nous expliquons
les short-hands,
les short-hands de CSS.
Donc, si vous vous en rajoutez
marge 0,
vous n'aurez pas marge 0.
Vous avez 4
différents classenames.
Pour le bouton top,
start et
end.
Parce que,
même si c'est plus de classenames,
encore,
on travaille sur Facebook.
Encore,
ça fait que c'est plus facile
de
faire des files
de multiple CSS.
Parce que,
même si
les source-offres sont
comme,
on veut un seul file de CSS
tout le temps,
il y a des petites exceptions
internavant.
Donc,
juste avoir
plus de lait de CSS
fait ça plus facile.
Mais aussi,
ça génère un file de
plus petit de CSS.
Et donc,
nous expérimentons
avec ça,
c'est quelque chose
que nous expérimentons,
que nous réalisons
que,
même si c'est
plus petit de CSS,
c'est un trait de source-offres.
Donc,
la source-offres
vous donne toutes les 3 options.
Des différentes
ways que vous pouvez
expérimenter les short-hands.
Il y a aussi des choses
de plus petit,
comme des queries de médias
et de la focus active.
Il y a beaucoup de détails
que je peux faire en depth,
mais
je vais vous dépasser pour maintenant.
Nous aimerons que vous puissiez
sponsoriser cette semaine.
Clirk.
Clirk offre
des managements de user
en bas de la box,
pour que vous puissiez construire
les apps plus vite
et ne pas vous inquieter
d'avoir l'authentification
dans votre app.
L'authentification est
une des choses
que vous pensez être plus facile,
vous ajoutez quelques tables
à votre database
et vous commencez à tracer les users.
Mais ensuite,
vous vous faites attirer
avec un flux de requises productives.
Vous devez avoir
d'authentification multifacte.
Vous devez avoir
des SOS,
pour que vous puissiez
mettre des contracts
de cool entreprise.
Avec Clirk,
ils vous dépassent tout pour vous.
Vous pouvez facilement
configurer tout ça.
Vous pouvez même avoir
des logins sociaux.
C'est un bêtis pour la set-up.
Et avec leur plan libre
qui offre
10 000 utilisateurs monthly,
vous ne pourrez pas payer
pour un peu d'un moment.
Même si vous êtes attirés
avec un phénomène viral
pour votre site,
et un peu de gens s'ignorent,
et ne vous utilisez
pas pour votre app,
vous ne vous payez pas.
Vous ne vous utilisez pas
pour les réels utilisateurs
dans votre app.
C'est cool.
Cette semaine,
je veux vous dépasser
quelque chose qui est
assez unique pour Clirk.
Comme nous avons discuté
sur le show avant,
l'opening source de la fonte
est une chose difficile.
Et ce n'est pas solide.
En plupart des cas,
les gens travaillent pour la liberté
et mettent les choses
pour les bonnes de leur coeur.
Mais cette semaine,
Clirk a fait
quelque chose super cool.
Ils ont acheté
Colin,
le créateur de Zod,
pour 3 mois,
pour travailler sur Zod.
Ils sont corporents
pour lui pour faire
le biais meilleur pour tout le monde.
C'est super cool.
Et nous devons vraiment
voir plus de ça.
Dès que Clirk
vous donne so much power,
with so little effort,
and their sponsors
of the community,
ça me fait penser
que c'est une compagnie
que vous devriez croire.
Donc si vous voulez
mettre l'authentification
dans votre app,
sans aucun ralenti,
head over to clirk.com
pour commencer.
Et si vous voulez
apprendre plus de Clirk,
pourquoi ils ont fait ça,
et comment on a été là,
vous pouvez aller au episode 75,
où nous interviewons
le co-founder Brayden.
Vous voulez trouver un autre
moyen de soutenir le podcast?
Beaucoup de membres
sur l'un des canaux que nous offrons,
ou head over to shop.debtools.fm
pour voir ce que nous avons sur sale.
Quoi-ce qui m'aide à garder le podcast?
Je pense que l'un des choses
plus difficiles
sur les styles atomiques,
qui est juste
comme une style de propriété
par classe,
c'est que
quand vous avez des classes
spécifiant
dans un élément HTML,
l'ordre est
comme
comment les styles
sont spécifiant dans la chute
pas dans l'ordre
de la chute.
Et je pense que
les gens qui se sont dit
que c'est un peu
spécifiant
dans les classes atomiques,
et je ne me souviens pas
d'un type qui m'a écrit
d'abord pour venir d'abord,
mais c'est
une ordre générale
qui m'intéresse
et je l'ai mis
dans quelques issues
et des situations

où ça peut
vous faire
battre.
Et je pense que
votre exemple
de margions
de la chute
est comme
que vous spécifiez
plutôt que
juste spécifiez
margons 0,
spécifiez
margons
de la chute
ou quelque chose.
Et
de cette façon
vous pouvez
peut-être
dépasser un de ces
phares
selon
où les choses
viennent
mais c'est
un
très
non ostentiel
de situation.
Donc
quand les gens me demandent
aujourd'hui
ce qui est unique
sur les styles
c'est le
margons de styles
plus que d'autres
parce que
ça change
donc
je ne les n'ai pas appelés
des avantages.

quand vous
utilisez les styles
c'est votre style de writing
dans l'objectif
et vous faites les
leur sur les éléments
dans un appel de function séparé
et des gens comme ça
et des gens qui n'aiment pas ça.
La winde de taille
est similaire
je pense que vous devez
apprendre le lingon de la winde de taille
et puis vous avez
à faire les choses en ligne
et c'est
vraiment
vraiment bon pour le prototyping
mais en temps
si votre liste de styles
se trouve vraiment large
c'est comme
ce qui est
ce qui est le cas
et si vous voulez
extracter ça
dans un variable
comme la winde de taille
ne fait pas très facile
de faire parce que c'est le cas
donc
il y a des
très
intéressants
décisions techniques
que la winde de taille
a dû faire
parce que
c'est un
très
très
thin
abstraction
c'est comme
généralement
un file de CSS
qui ne touche pas
votre code source
et
ça
commence à causer
un peu de constraints
sur ce que taille winde peut faire
comme
vous ne pouvez pas
juste bouger les styles
à n'importe où vous voulez
comme vous devez
mettre les styles
dans un certain
pattern
pour que
le jit peut détecter
depuis que
nous avons un compiler
comme on est
littéralement transformé
dans vos files de JavaScript
nous
avons
beaucoup plus
de
flexibilité sur ce que nous pouvons faire
donc
un est comme
vous pouvez appliquer
autant de styles que vous voulez
et nous allons
vous faire
faire
ce qu'on a
et vous allez
mettre
tous ces styles
dans un compile
et
seulement
appliquer
ce que vous avez
perdu
donc
vous pouvez juste
suivre
les styles
de base
et les styles de override
et vous ne vous devez pas
penser
sur les
courtes
hands
ou les queries
ou tout
vous devez
juste être
comme ça
etc
بين les 196

par avec
le
first
game

0
1
1
1
2


et des styles générés.
Ce qui est intéressant, c'est que vous pouvez faire ça en travers les files
et puis vous payez un peu de faute en mergant les noms de classe à runtime.
Nous générons des objets de noms de classe, nous les mergons en runtime,
mais tout est encore juste consistant et la faute est super lourde,
ce n'est pas plus grand que les noms de classe.
C'est l'aide de tous les uns qui ont été utilisés en ce moment.
Je l'ai fait avec un truc contre la merge des taillements.
La merge des taillements a aussi quelque chose qui est similaire à ceci,
c'est la merge des taillements.
La merge des taillements est une des deux très grandes
parce que ça doit être encroché par tous les exceptions dans la mer.
Et ça doit être en train de se faire avec les mains courtes et tout.
Mais aussi, c'est en train de se faire avec les noms, pas avec les objets.
C'est plus lent pour les mergers.
C'est un peu plus lent pour les mains courtes.
Et parce que nous avons un compiler, nous pouvons générer le plus rapide pour vous.
Nous pouvons le remerger si vous voulez.
Nous ne pouvons pas le faire, mais nous pouvons les retirer de nouveaux styles.
Tout ça.
Le compiler a un peu d'objets,
comme des constraints à la fin,
où vous ne pouvez pas utiliser ça dans un go.
Si vous avez écrit votre code de sel et un go,
vous ne pouvez pas utiliser des stylewins.
Vous ne pouvez pas utiliser des stylewind.
Mais si vous avez écrit des components de JavaScript,
alors on a un plugin de Babel,
vous pouvez le faire.
C'est ce que le compiler fait.
C'est de regarder les noms de la classe
et de faire tout ça,
et de créer un outil statique.
Donc, le compiler a beaucoup de choses
que le file,
donc dans le design, il n'y a pas de compilation du file cross.
C'est un limitation de Babel,
est-ce que vous n'avez pas fait ça ?
D'un à un point, oui.
Mais ce n'est pas pourquoi nous n'avons pas fait ça.
Nous pouvons cacher chaque file individuellement.
Et c'est comme nous gardons nos builds.
Nous avons des files de la classe,
et nous avons des files de la classe.
Nous avons des files de la classe,


et nous avons des files de la classe.


Nous avons des files de la classe,
et nous avons des files de la classe.
Nous avons des files de la classe,





Nous avons des files de la classe,

et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,


et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,







et nous avons des files de la classe,
et nous avons des files de la classe,







et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,






et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,


et nous avons des files de la classe,

et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,
et nous avons des files de la classe,
diese étude whole
style x.
Yeah, there was no competition in terms of like nobody was like, we want to use this instead.
There was a lot of weird patterns that came up.
So style x is honestly like, in my opinion, it's too flexible on what you can do with it.
So depending on your like style of what you want to do, you can use it in different ways.
So just to give you like a couple of examples, one is like people who like the tailwind way of doing it.
They like to define a bunch of utilities and a file.
So like, there's certain parts of Facebook that work like this, where they define like all of the margins that they want to use in their product and all of the paddings they want to use in their product.
And they just define them in a single file.
And then all over the place, they just import margins dot small and then they just use that.
And so it feels much more like tailwind if you use it like that, because it's just all of these values exist, you import and use them.
You don't have to rewrite the styles every time.
Conversely, there's also people who write the same styles and then use it in like 10 different components.
So they need different components for whatever functional reasons, but they should look identical so they can extract that out.
So just the way it works, Stylix gives you enough flexibility that people who have like different desires from how they want to architect that code, they could let them do that.
What is like the longest running thing that people always want, which we still haven't done, is like nested selectors.
So like, oh, if the parent is hovered, then the child should do this type of stuff.
We have a couple of hacks that I will not elaborate on because more people will start using it.
There's a couple of hacks that we've used internally, and it's like used in five places and like we kind of don't want anyone to do that.
Because we also like spoke to the people at Microsoft.
So Microsoft has something very similar, which I didn't know about like till much later called Gryffle.
And they made a couple of mistakes, in my opinion, sorry, where, and they are like kind of regretting these decisions where early on they leaned super hard in the favor of even more flexibility than what Stylix gives you.
And so they have run into two problems.
They solved one of them.
One of them was compile times.
So they let you like import whatever and just use it wherever there wasn't like file level caching that Stylix is designed for.
And so they had this problem of like, oh, our build times are too long.
And so they like rewrote the entire infrastructure and how they compile.
And I don't know how well that is work, but I know that helps quite a bit.
The other one is, even though they also generate atomic styles, their styles got huge, like they reached a megabyte, I think.
And that's because they allow people to just write arbitrary selectors.
So there's just people writing all sorts of arbitrary selectors.
And then, okay, at that point, you can't control the amount of CSS.
You're not reusing CSS as much people started writing, you know, custom class names all over the place.
And I have a long standing RFC on the Stylix repo, trying to figure out what's the best way to tackle it.
I quite like actually the solution that tailwind used to have.
They still have it, but they added more stuff that I disagree with.
But they started with group and peer, which is a very limited amount of what you can do.
And then recently, I think they added like, oh, you can just do child selectors and stuff.
And I'm like, no, don't do that.
I think that's the biggest mistake tailwind has ever made, is adding support for that.
Yeah, those styles or class names, those are just so hard to read.
Even when I write them myself, I come back to them and I'm like, I should not have wrote them that way.
And it really speaks to one of the other like powers of Stylix and like defining your styles like that is like, you have an extra layer of naming.
So it's like, my active state isn't this like three screen long thing.
It's like an entity that I can go look at and can expand and become more complex without giving me more mental burden.
This is actually one of the most controversial decisions about Stylix right now is like, people are like, why can't I write my styles as an inline object?
And we have a discussion about it.
And my basic takeaway was, yes, it's a little more annoying up front because you're forced to name everything.
But then when you're reading code, you're like, OK, these are base styles, these are focus styles, these are active styles, and you don't need to know what those styles are every time.
And so it actually leads to a better, more maintainable code base.
And a lot of people disagree with me on this, but like, currently, whoa, our like escape hatch for that is since it's just a Babel plugin, you can have a Babel plugin before Stylix.
And so there's some community members who've literally created like a new function for Stylix in a separate Babel plugin that lets you write styles in line, if you want.
And, and I have written a separate Babel plugin that lets you write tailwind.
So a friend of mine was like, I want to use tailwind and I want to use Shad CN, but I also want to use Stylix because I want these features from Stylix, but I want this fast prototyping from tailwind.
So you can just compile tailwind to Stylix and it just works. That's fine.
That's awesome.
Yeah, it's a pretty clever solution.
I think that, you know, the, the nicety of like having a Babel pipeline is that pretty easy to transform nature of it.
And I guess the, the, the profile, I can also see like the profile compilation, helping with build times in particular, because you know, the caching part of that would be pretty hard, especially with a code base as big as Metas.
Like if you're running Babel over the whole thing, every time you would churn a lot of CPU cycles, I imagine.
I did have a question about that. So is it, is it really just like per file?
And, and I think part of the question here is like kind of intrinsic to how meta architects like components per file and things, because I think in a lot of like systems that I've seen is you'll have like a components folder somewhere, and you'll have like a set of like small components or say it's like a larger products, you'll have like a,
you know, a feature directory, and then you'll have some components for there and then like some layouts and stuff and some of those files are really small.
And then sure, there may be some like reused classes there, but there's not going to be a ton of them. And if you're processing per file, are you just like regenerating the atomic classes uniquely for each file?
Or is it still like a combination of like sort of like a deterministic way is like, oh no, we'll have the same class names over the whole set of the style sheet.
It's 100% deterministic. So stylists works entirely based on hashing. So if you write margin zero, it's going to be hashed into a particular class name. And no matter where you use it, it's the same hash.
And if I'm understanding your question correctly, the way it works is, let's start with just styles, like when we get into variables, things get a little strange. That was something it took a while to solve.
But let's just say we're defining styles, styles are defined in style of inside of a stylics.create call. We compile it, we hash every style we generate class names.
And that's what is generated as the output of the JavaScript. And then as metadata, we generate the CSS that this file wants to inject into the CSS file.
And so the JavaScript transform is completely cashable. The same input will always have the same output. It will never change.
The metadata included, the generated styles included. So all we have to do when we change, let's say there's like 1000 files and we change one file.
All we have to do is we regenerate that one file, get the new output from that file, and then we take the old output from all of the other files and we just generate the CSS file, which is just going through these list of class names essentially,
deduping them, it's just merging an object, and then outputting the CSS file.
So that part, even if it's like 100,000 files, which we do have something like that, it doesn't take long.
So to give you like what we used to have before we put caching in place, it was not like every build was super slow at in production or whatever, because there was a different level of caching for the whole repo sort of.
But every single time an engineer like opened a Dev server to like work. The first time they opened Facebook dot com and development style X was taking a minute and a half.
And so they would be like, okay, let me like open newsfeed and see how long it takes. And everything else is already pretty heavy on Facebook.
It's a big thing and it's booting up hack and stuff. And on top of that, there's another one and a half minutes of just transforming every single file.
And that was not like feasible. And then I did a basic amount of like optimization just using nodes like workers, like parallelize that that brought it down to like 30 seconds.
And then we did caching and now it's like couple of like a few seconds. And the merging of all styles to generate the CSS file was never more than like two seconds ever.
So that's fine. That's not the bottleneck. The bottleneck was just compiling so many files. And now we don't like we now compile maybe a handful.
Where where is that caching happening? Is it like a babel cache? Or is it like some like internal Facebook thing?
That's an internal Facebook thing. It's a forget what it's called. But it's like an Facebook version of a normal key value door like think red is but not red is something else.
It's a simple cache. It can be done even even an open source. So the roll up plugin, if you run it and watch more does caching, it'll only compile files that have changed.
And roll up also has an op. I think it's a separate thing where you have to turn it on, but you can have a file system cache for roll up, where it will write everything to a file system.
So if you opt into those things, you get the caching even with roll up. And it's theoretically possible with every bundler. But if you ask me what I've been struggling with this, making every bundler do good things well.
What bundler have you been struggling with the most?
We're back. Hands down.
Why is that?
It's because basically every other bundler has more or less decided that roll up got the API right. And, and it's very sensible and I remember I wrote the first version of roll up in a day, and then I added the caching within another day.
And Webpack probably spent more than a month on it. And it's still the jankiest plugin.
And actually, we actually wrote a whole CLI, like a separate, it uses Watchmen and it just watches the whole directory and compiles it.
Simply because Webpack is such a mess and it wasn't working well in Next.js.
And so we have a whole CLI, it should come out in the next release. It's not, it's not released yet, but it's merged.
And some community members are like working on better Webpack plugins.
So hopefully we'll solve that. But like right now, that's probably the worst thing about Stylix that I want to get solved.
What is the big impetus? What is the big push to getting, you know, Webpack plugins and more community, I guess, bundler support?
I know this is attention within Meta sometimes of like, you know, focusing on infrastructure that supports product versus like, you know, continuing to push on open source.
So what's the sort of like driving factor for that right now?
Yeah, I mean, there is some conflict there because there's no direct benefit that we will get from a Webpack plugin or any bundler plugin, really.
And so we actually like officially decided not to support every bundler under the sun.
So there's no official parcel plugin or official RS bar plugin or anything.
We made like a few and Webpack is just really big because of Next.js, honestly.
And Storybook is like the other one, like a lot of people use Storybook and Storybook uses Webpack.
So is this blocking a lot of people, honestly, if everybody was on VTOR roll up already, it wouldn't be as much of a problem, but there's a very large number of people who still need Webpack to work.
And if we don't fix it, then like, they can't really participate in the community.
And so my argument is that for stylists to be successful product project, we need people to like use it and contribute back.
And if you make Webpack work well, then there'll be a bigger community which eventually helps us.
So it's a back and forth with, you know, the management, whatever, to explain why it actually makes sense for us, put some time into it.
But I think it's fine as long as I'm not like sinking all my time into it, which if I tried to do too much, I probably would.
I personally am a Webpack user, so I'd love if you made it work on Webpack. Webpack, it's a double-edged sword.
It's like the plugin system is like you have access to every part of the car and you can hook into every part of the car, but that also means you need to know how the car works, which is a very big challenge.
And that's the problem because like we have a Webpack plugin and it's functional, but every single like framework out there, like Storybook uses Webpack in a very strange way.
And so if you were doing a vanilla Webpack bundle, it works fine, but it's like, oh, in Next.js, we need all this extra weird stuff because like with the app directory, there's actually not one bundle.
There's actually three bundles, and now you need to like shuffle styles from one bundle to the other bundle.
And there's like all these piles of hacks that I had to do, and they don't work very well, obviously.
But so, and the caching breaks and things like that.
So the biggest problem with Webpack is like it'll work some of the times, but it'll always break caching.
And actually, I'm like very hopeful because there's a community member, he built a Webpack plugin outside and they're like, this works way better.
It works with Next.js.
It came out last week. I have to like dig into it, test it more.
But I'm hopeful that somebody's finally solved this problem for us.
Yeah, I think trying to customize Webpack like you are is a hard task.
Like we talked to Zach, the guy behind Module Federation.
And just for like the last year, every time he talks about Next.js, it is not in a good light and it's because of like actually customizing its Webpack configuration is not simple.
Yeah, and I spoke to Tobias actually, like the creator of Webpack.
And I have this long issue that I wrote from based on my conversation with him.
And he suggested basically inlining the CSS generated from each file because he was like, there's no other clean way.
Like what he suggested was Haki as well because he knows that it can, it's too flexible and it can be used in weird ways.
Because what we want is actually fairly simple.
We just want a Babel step and just take some metadata and put it together.
It's not theoretically super complicated, which is why I was shocked.
That was so hard to do with Webpack.
And like the other implementations use like virtual files and virtual file imports.
And I like resisted that because like I tried that once and that slows everything down a lot because now you have like 2x the files that you need to process.
And then you have these CSS files where you started with JSON, you generate CSS, you pass the CSS back into JSON, and then you merge it and then you generate CSS again.
And I'm like, it's really wasteful to do that.
But that's what most people end up doing with Webpack because there's nothing else that works consistently.
Yeah, unfortunately, and I think sort of more to your point is this like next.js in particular has really squeezed like every little bit.
They can't add a Webpack and to like bend it to their will, they have done some rather un holy things.
That's kind of hard to decouple.
So, you know, just congrats on getting it to work at all.
Honestly, I know like having dug into that for a few issues, it's impressive and intimidating and yeah, there'll be dragons for sure.
It's really hacky.
Like, I'm using some like memory object to source data from one bundle in another and, you know, throwing promises and like not like letting them resolve so that I can wait for the other bundle.
It's a big mess.
It's not great.
And I've been working with them like I've been talking to the next.js team.
They added the support for React compiler recently, which is a Babel plugin.
And so I'm hopeful that there's like a new pathway to integrate stylics without opting out of TurboPack and opting out of SWC for everything else, because that wasn't possible before.
And it's now possible and next 15.
So I'm digging into that just, you know, time.
Do you see the team working on integrating with SWC or any of the newer AST tools?
Not in the short term, honestly.
There's like very little benefit for us to do that.
Like we don't use SWC internally.
If there was some tooling that supported Flow, like if SWC supported Flow Syntax, then there would be a reason for us to do it.
And currently, no, I have started it.
I have a branch where I've written maybe like three of the files in Rust.
But like, it's a moving target.
So I can't, I can't keep working on the Rust implementation when the JavaScript implementation is changing so often.
Maybe once it stabilizes, I'll do it in my free time or something.
But like, Meta doesn't care about that as a company.
Like it will give us zero benefit internally.
So not yet.
So you mentioned one of the, I guess, not so internal programming languages.
Facebook has their Flow.
You've been tweeting about Flow a lot and you seem to think it's better than TypeScript.
So can you tell me why you think it's better than TypeScript?
Okay.
Let me, let me say it's not like better at everything.
It's better at safety and correctness.
It's worse at developer experience.
So developer experience falls into, let me double the things that it's bad at first,
because that probably makes sense to everyone.
There's two aspects of developer experience where Flow kind of sucks.
One is just the tooling.
So yeah, SWC and ES Build and bun and Dino,
they all support TypeScript syntax natively now.
Nothing supports Flow natively.
And so if you're using Flow, you need a Babel plugin and then you need a special syntax plugin for Babel now
if you want to use all of the newest features.
And so just setting it up has become worse and worse over time.
It used to be better than TypeScript once upon a time because it was like supported natively in Babel
and TypeScript was not, but that has long not been the case anymore.
Like TypeScript is way better if you want to integrate it into a project
that you have to set up way less stuff today.
VS Code plugin for TypeScript, way better.
Pretty like the type arrows.
I want to say on par, but at least there's some plugins that make TypeScript slightly better.
Just the community of TypeScript's way better.
Again, if you're looking for type definition files for TypeScript,
there's basically everything and Flow doesn't.
So community tooling, Flow is worse.
We all know that.
The other one in how the type system itself works,
TypeScript is very, very in favor of just giving you every feature possible.
So TypeScript gives you template string types.
So people have written parsers in types and it goes insane.
And it also makes you write less type definitions.
So in TypeScript, you can just omit the return types of functions always.
So Flow makes you write more types in some of those cases.
Flow makes you write all types for exports in every single file.
So developer experience a little bit worse.
Now why is it actually better at its core?
Is because let's start with the original design decision that TypeScript made,
which is variance checks.
Now this gets really nerdy and I don't think a lot of people will understand.
But let me ask you a question.
Is a cat an animal?
Yeah.
Okay, yes.
If a cat is an animal, is an array of cats an array of animals?
Yeah, not necessarily.
Justins right there, exactly.
So this is the core conflict between Flow and TypeScript.
TypeScript decided that most people will say yes, like you did Andrew.
And so they just made it so, which is wrong.
Okay, and why is it wrong?
It's only wrong because javascript is, because arrays are mutable.
Because if you have an array of animals, you can push on an array of dogs to it.
You can push on, like you can push on, you know, not a cat to it.
But like if you start calling an array of cats an array of animals,
now suddenly you're allowed to push any animal into it, not just cats.
And the problem only comes with mutation, not reading.
And so Flow had this feature first and TypeScript also added it later.
There's these read only types.
So you have arrays, but you also have read only arrays.
So an array of cats is a read only array of animals,
but it's not a mutable array of animals to be fully correct.
And so this behavior is done correctly in Flow,
where if you try to call it a mutable array of animals,
Flow will give you a type error right there.
And TypeScript will tell you nothing, it will just let you do whatever.
So you can have an array of cats, call it an array of animals on the next line,
and then push a dog into it and you'll get no type error.
And so if you don't care about that, then TypeScript is probably fine a lot of the times.
A lot of people think they don't care about that,
but this is why you have these edge cases in TypeScript,
where things are wrong and you don't know why,
because it's purposely just letting you be slightly wrong some of the times.
And so that's one big reason why Flow is better.
There's smaller things like the as costing.
In TypeScript, you can just cast a string to a specific string,
which it's not, and it does no checking.
And Flow does.
If you're doing something unsafe in Flow, you have to go through the any type first.
That's the only way to do it.
TypeScript, you can just do it in random other places,
and that feels very scary to me.
That might be a little nerdy and be like,
most people will be like, I don't care about that.
Let me give you the very specific,
why don't we have this in TypeScript so far type of features?
Like, and if TypeScript added them,
they would probably fix 80% of my complaints.
There's two features,
exact object types and opaque types.
Opéca types is easier to understand.
I also care about it less because TypeScript people use this feature
called unique symbols in TypeScript,
and they abuse it and they like create these tags and this messy stuff.
And all of that is just a hack around the fact
that there's no opaque types in TypeScript.
Fine, it's a hack, but at least it works.
There's no hack to make exact object types in TypeScript.
And that is a feature that should be there,
and I don't understand why it's not there,
and it's so annoying,
and there's like a six-year-old issue on TypeScript,
but people are like, please add it, please add it, please add it.
They're like, what's the use case,
and people keep giving them use cases and they don't understand.
And I can give you the simplest use case.
I have a component, it takes a style object.
The style object can have color or background color, nothing else.
TypeScript will always let you pass in extra stuff for no reason.
And so you have to manually do runtime checks
and block out just those keys,
and you made your runtime slower
just to get around the fact that TypeScript won't let you say nothing else.
And Flow made this change a few years ago,
Flow didn't always have this feature either,
but it's like a game changer.
It's like so useful as a feature.
I don't understand why this one feature is not in TypeScript.
So that's my biggest reason.
The Type system itself is pretty nice.
And finally, the big thing,
this most people don't care about outside of Facebook,
is it's like way faster at scale,
and it's faster for two reasons.
One, it's written in OCaml, which is a native language,
which is also its downfall in many ways
because nobody wants to contribute to it.
But the other reason is some of those like DevX losses early on,
you have to write more types out.
Let's Flow do less work,
because it made you write it out.
So for performance sake, that makes sense.
Yeah, I mean, it's interesting that you say that though,
because so JSR, the new JavaScript registry from the Dino team,
has this thing called like slow types,
where they're like, oh, like, you know,
doing type inference and stuff is actually really slow
if we have to do everything.
So we want you to be really explicit,
like, you know, type all of your returns, you know,
for everything, and we can like generate
better type documentation and stuff for that.
So it's like, I think, you know, TypeScript
really started to be like very flexible.
And, you know, like the structural typing
and everything that it did is like,
it's not a very sound type system.
I guess it's a lot more, it's getting more and more sound
as time goes on, but it's like,
it was not very sound in the beginning at all.
And I thought that like Flow is always more like,
more concerned with sound mess.
It's like we actually want to have like more confidence
with types.
Let me give you one other thing that I heard
from the static Hermes team.
So have you heard of static Hermes?
Yes.
And so I was on a flight with the person,
Shreitan, who like gave a talk about it.
Like if you've seen the talk showing off
static Hermes, that was him.
And I was like talking to him and although TypeScript
is kind of supported, they are struggling with
the lack of exact object types as well,
because an exact object type can basically
be compiled into a struct in binary code.
But an inexact object type, like an open record
in functional language terms,
like that's an open record that has to be compiled
into some kind of hash map with like dynamic key lookup.
So it's going to be slower.
And so leave everything else out,
like it will compile to slower code as well,
like if you don't have exact object type.
And I don't know, like this is one feature
where I feel like there's no excuse for TypeScript
not to add it.
It makes sense in every principle that TypeScript has.
It's not a correctness thing.
It's not a purity thing.
It's just practical, useful feature for end developers.
And this is the one where I don't know why they have
such a hard resistance to this feature.
I'm sure it's some like performance
or internal implementation or some like
really deep gnarly gotcha.
Yeah, I think it's some sort of internal implementation
thing.
People have done some weird hacks where it sort of works.
I've done a hack in stylics,
which is I had to write every single key,
like in every single known CSS property.
And when you say this is the styles I want,
I said everything else to never.
And so at least you can't pass other known styles.
You can only pass unknown styles.
So that's something.
So I know we just talked about flow for a long time,
but one more question on languages
before we move on to our final question.
There is something we haven't talked about
that you think, I think,
is the language we should all be using to write code.
What is that language?
I know what you're referring to.
So I think you're referring to Swift,
which is, I'm not going to say
that's the language we should all be using
to write code instead of JavaScript.
I think it's the language we should be using instead of Rust.
So my take there is,
not all Rust projects, let me be clear.
So I think Rust is in this place
where it's a very, very fast, low-level language,
which is great for writing kernels and stuff.
And it's nice enough that people have started writing products
and there's like UI libraries and stuff like that written in Rust.
And all of this JavaScript tooling
is being written in Rust, SWC, etc.
And I think those things where,
if we don't care about 10% of our performance hit,
then Swift is a better language than Rust
because it's easier.
It's still not garbage collected,
there's no garbage collector,
but the memory management feels automatic.
It's not a borrow checker by default.
You just write things like you do in JavaScript
and they work without a garbage collector
because it's just doing counting.
So the compiler sees when you take a value
and it puts in some calls and it's fine.
It gives you a 5-10% hit in total performance
but it's fast enough for most things.
And it looks like JavaScript, it's easier to pick up
and it has all of the other benefits that Rust has.
It compiles to Wasm, it compiles on all platforms.
And this is one of my, like, another secret reason
I really want Swift to be a language
that's used for JavaScript tooling,
is it has interop with C++.
So Rust has interop with C.
So you can use FFI to use C code in Rust and Rust code in C.
But you can't use C++
and actually almost no language interrupts with C++
because C++ is a mess
and Swift does now very recently.
And that's when I started talking about Swift a lot.
Actually, it's like when they added support for C++ interop
because Hermes is written in C++.
All of the flow tooling is based on the Hermes parser at this point.
And so my secret aim here is like,
hey, we could create a new tooling based on Swift
and that would support flow without writing a new parser.
And that's one of the other reasons.
Yeah, I found it really interesting to learn
that the creator of Rust actually works on the Swift team
and has for the last half decade.
So they're almost sister languages.
Yes, they started around the same time
the creator of Rust moved to Swift.
Rust has copied some features from Swift
and Swift is copying features from Rust.
They're actually very similar.
I just think they're slightly different levels
because when I'm like, as I said,
like I have written some Rust,
I've been trying to slowly write an SWC plugin,
probably take a year at this base more than that.
But what like really struck me about it
is even though it's not necessarily hard all the time,
it feels very tedious
in the amount of just busy stuff that you have to do in Rust
compared to Swift or JavaScript,
you have to constantly unwrap values
and constantly clone them.
You have to do all of this stuff manually
where Rust goes super hard on making every single thing
that could cost you even a drop of performance explicit.
You must know that you created a copy here.
You must know that you incremented a counter here,
every single thing.
And Swift is just automatic in all of those things.
It will create copies when you need to.
It won't create copies when you don't need to.
I feel like Rust is too low level
for the kinds of things we're doing with it.
If you're writing a kernel, if you're writing an operating system,
yeah, still probably Rust is the better language.
Even a browser, I know that Firefox uses a bunch of Rust.
I'm not going to tell them to switch to Swift.
That makes no sense. Rust is the better language there.
A JavaScript bundle could probably be Swift and be fine.
And be nicer to write plugins for,
especially for JS Devs,
because Swift looks way more like JavaScript than Rust does.
Yeah, I think it's an interesting take.
I mean, I'd say broadly...
Non, non, non, non, I wasn't saying that negatively.
I mean, I think broadly that I do agree
with your perspective here, though,
that it's like Rust, there is a cost to Rust.
I've written a lot of Rust over the last few years,
I write a lot of Rust every day.
And there is a real cost to it.
And especially for application level things,
it can be the right thing in some cases.
If you're trying to squeeze out a lot of performance,
I think the case of building games or something like that
that probably make a lot of sense.
And if you decide to do it for other application level things,
you are going to pay that kind of continual cost.
It's just going to be 20% harder
than it may need to be otherwise.
And I think there's a lot of languages in this mid-tier
that is one level of complexity below,
or I guess one level of difficulty
easier than what Rust is,
that give you a lot of value.
And then, honestly, for a lot of applications,
I just feel like there's so much tooling opportunity.
Of course, there's Swift, there's Go,
there's even traditional things,
like doing things on the JVM,
which kind of shutter,
Kotlin is pretty decent.
And yeah, there's just a lot of good...
Kotlin's pretty nice.
So Kotlin, I saw, and it looks like Swift.
They look surprisingly similar,
like they both use funk,
with the keyword and stuff.
I would say that Kotlin, Go and Swift
are in the same area of overall throughput of performance.
What sets Swift apart from Kotlin and Go
is the garbage collector.
So Swift isn't garbage collected,
so I think they are suited for different things.
So when you care about throughput and not consistency,
like servers, Go and Kotlin, it's great.
If you're doing UI,
where you don't want a GC pause ever,
Swift's better,
and then bundlers, you could go either way,
it would probably be fine.
Yeah, and I think in terms of how it would feel to use it,
it's more rusty than Go.
Go feels...
There's people who love Go and hate Rust,
and there's people who love Rust and hate Go,
because Go doesn't have a rich type system,
and doesn't have type...
What do you call them?
Some types, essentially.
Enums with data.
And Swift has that, and Rust has that,
and Go and Kotlin don't.
So if you get addicted to those type system features,
then Swift will still give you all the niceness,
which Rust gives you,
but also gives you the downside,
which is like Rust,
Swift has a very slow compile time itself,
and Go is super fast compiling.
So trade-offs.
But that's why I said,
it replaces Rust for the throttle of applications.
I don't think it replaces Go or Kotlin
for what they are used for.
Their server infrastructure is really big on the JVM,
and also Go at this point.
And Swift on the server,
while, as a language, it's great,
even for the server.
It has every feature you might ever want
for a server app.
The ecosystem just isn't there.
So maybe in a few years,
it'll be a good contender,
but right now, it's a smaller ecosystem.
Hosting is harder, all of that.
They had Swift for Windows came out,
not too terribly long ago, right?
So Swift for Windows has actually been out
for a few years,
but it used to lag behind the Mac version.
So they shipped, I don't know,
regular expressions,
but then it didn't come to Windows
until later and stuff.
But then this company,
the browser company,
who makes Arc.
Oh, right.
Yeah, so they built Arc for Windows with Swift.
So they could just take their code
from Mac and just bring it to Windows.
And when they did that,
they hired one of the people
who used to work on Swift for Windows
and basically funded his work.
And now Swift for Windows
is basically on par,
and it's kept up to date.
And they also did a bunch of work
to take the C++ libraries from Windows
for UI and connected it to Swift.
So they were like,
we don't want GC pauses in our app.
That's one of the reasons
they chose Swift,
is because C-sharp is garbage collected
and JavaScript is garbage collected.
And they're like,
all of these UI frameworks on Windows
are actually garbage collected.
We want something that's as fast as possible.
So they took the lower level C++ stuff
and like,
put it, mapped it with Swift.
And that's how they built Arc for Windows.
That's really awesome.
So I did a test.
Like, I did a test of compiling
like a function of Swift
with VS Code on Windows.
They worked.
Sweet.
I have to try it out.
I haven't played with Swift for a long time.
I need to give it another go.
Cool.
So before we wrap up,
we always like to ask a future facing question.
So you spent a good bit of time now
working on Stylex.
What do you think is the future of styling?
Both maybe where you want to take Stylex,
but like,
especially in the category of like CSS and JS,
like what is the future in this space?
Okay,
this is going to fly to your big concept.
There's like three levels to it.
One is short term.
I think everything is going to go like build time.
I think runtime CSS and JS was a mistake.
So Stylex is build time.
Yeah, like, it'll be a long tail.
People will slowly move off of it.
But runtime CSS and JS is just always going to have problems.
But like longer, longer term,
I think that CSS itself,
like as a language is moving so fast
and there's so much cool stuff that's come out in CSS,
like it could have a whole episode about that.
And I think sooner or later,
they will solve Tailwind,
essentially, where you won't need a tool.
Like, you'll just be able to write inline CSS
and be able to write media queries
and pseudo selectors inline on an element
and have it work.
Like, as soon as that comes natively,
like we won't need a lot of the tools
that we use most of the time.
At that point, even something like Stylex
would become much, much smaller,
where I don't think the need for it would go away entirely,
simply because merging of styles
needs some manual checking of things.
But it could probably become
a really small helper tool to merge styles.
So that's where I think Styling is going on the web.
In terms of where my work is going with Stylex
as well is ReactStrick DOM.
So ReactStrick DOM, it's open source,
it's still experimental.
I had a talk at ReactCon
where I talked about React Native and ReactStrick DOM.
And a lot of the design decisions
of Stylex were made for that.
Like, how do we make something
that's not dependent on a CSS engine
in any way from an API point of view?
And so I think on the Stylex side,
we will fill out some of the missing features.
We're looking into the descended selector stuff.
There's smaller details of...
When you use lots of media queries,
can we find ways to share them?
Can we find ways to unify them?
Stuff like small cleanup stuff.
Nothing specific to point out.
But then to bring all of those concepts
to ReactStrick DOM.
Right now, a lot of it is just done at runtime
on ReactStrick DOM,
parce que, again,
on n'a pas de la même constraination
que la web sur React Native.
Il n'y a pas de service hydrant.
Mais c'est en arrivant.
On a des components sur React Native.
Il y a un truc par Evan Bacon
qui est un des meilleurs talks
sur ReactConf, si vous voulez voir.
Et quand ça vient,
la performance va toujours être importante.
On va commencer à faire
le même concept
que React Native.
On va faire un peu de compilation
pour plus de choses.
En même temps, il y a des chrétiques
et tout ça.
Mais le même truc s'applique
à la implementation style.
Je sais que
beaucoup de gens vont être malades,
mais il y aura plus de compilation.
On va changer
les choses dans la plateforme
et on va trouver des choses
pour compiler.
On va continuer.
Je suis d'accord.
Je suis stélial,
pas de build.
C'est parti pour nos questions.
Merci pour votre attention.
C'était un bon look
sur comment Facebook
utilise les CSS
et les styles.
Merci pour votre attention.
Je vous aime.
Je vous aime.
Je vous aime.
Merci.
C'est génial.
Je vous aime.
Je vous aime.
Merci.
Merci.
Merci.
Merci.




Merci.

Les infos glanées

Je suis une fonctionnalité encore en dévelopement

Signaler une erreur

devtools.fm:DeveloperTools,OpenSource,SoftwareDevelopment

A podcast about developer tools and the people who make them. Join us as we embark on a journey to explore modern developer tooling and interview the people who make it possible. We love talking to the creators front-end frameworks (React, Solid, Svelte, Vue, Angular, etc), JavaScript and TypeScript runtimes (Node, Deno, Bun), Languages (Unison, Elixor, Rust, Zig), web tech (WASM, Web Containers, WebGPU, WebGL), database providers (Turso, Planetscale, Supabase, EdgeDB), and platforms (SST, AWS, Vercel, Netlify, Fly.io).
Tags
Card title

Lien du podcast

[{'term': 'Technology', 'label': None, 'scheme': 'http://www.itunes.com/'}]

Go somewhere