style9: CSS en tiempo de compilación en JS | Programar Plus

En abril del año pasado, Facebook reveló su nuevo gran rediseño. Un proyecto ambicioso, fue la reconstrucción de un sitio grande con una gran cantidad de usuarios. Para lograr esto, utilizaron varias tecnologías que crearon y de código abierto, como React, GraphQL, Relay y una nueva biblioteca CSS-in-JS llamada stylex.

Esta nueva biblioteca es interna de Facebook, pero han compartido suficiente información sobre ella para hacer posible una implementación de código abierto, style9.

¿Por qué otra biblioteca CIJ?

Ya hay muchas bibliotecas CSS-in-JS (CIJ), por lo que puede que no sea obvio por qué se necesita otra. style9 tiene los mismos beneficios que todas las demás soluciones CIJ, tal como lo articuló Christopher Chedeau, incluidos los selectores de alcance, la eliminación de código muerto, la resolución determinista y la capacidad de compartir valores entre CSS y JavaScript.

Sin embargo, hay un par de cosas que hacen que style9 sea único.

tiempo de ejecución mínimo

Aunque los estilos se definen en JavaScript, el compilador los extrae en un archivo CSS normal. Eso significa que no se envían estilos en su archivo JavaScript final. Lo único que queda son los nombres de las clases finales, que el tiempo de ejecución mínimo aplicará condicionalmente, tal como lo haría normalmente. Esto da como resultado paquetes de código más pequeños, una reducción en el uso de la memoria y una representación más rápida.

Dado que los valores se extraen en tiempo de compilación, no se pueden usar valores verdaderamente dinámicos. Afortunadamente, estos no son muy comunes y, dado que son únicos, no se ven afectados por su definición en línea. Lo que es más común es la aplicación condicional de estilos, que por supuesto es compatible. También lo son las constantes locales y las expresiones matemáticas, gracias a babel. path.evaluate.

salida atómica

Debido a cómo funciona style9, cada declaración de propiedad se puede convertir en su propia clase con una sola propiedad. Así, por ejemplo, si usamos opacity: 0 en varios lugares de nuestro código, solo existirá una vez en el CSS generado. El beneficio de esto es que el archivo CSS crece con la cantidad de declaraciones únicas, no con la cantidad total de declaraciones. Dado que la mayoría de las propiedades se utilizan muchas veces, esto puede dar lugar a archivos CSS considerablemente más pequeños. Por ejemplo, la antigua página de inicio de Facebook usaba 413 KB de CSS comprimido con gzip. El rediseño usa 74 KB para todas las páginas. Una vez más, un tamaño de archivo más pequeño conduce a un mejor rendimiento.

Diapositiva de Building the New Facebook with React and Relay de Frank Yan, a las 13:23 que muestra la escala logarítmica de CSS atómico.

Algunos pueden quejarse de esto, que los nombres de clase generados no son semánticos, que son opacos e ignoran la cascada. Esto es verdad. Estamos tratando a CSS como un objetivo de compilación. Pero por una buena razón. Al cuestionar las mejores prácticas previamente asumidas, podemos mejorar tanto la experiencia del usuario como la del desarrollador.

Además, style9 tiene muchas otras excelentes características, que incluyen: estilos escritos usando TypeScript, eliminación de estilos no utilizados, la capacidad de usar variables de JavaScript y soporte para consultas de medios, pseudo-selectores y fotogramas clave.

Aquí está cómo usarlo

Primero, instálalo como de costumbre:

npm install style9

style9 tiene complementos para Rollup, Webpack, Gatsby y Next.js, todos ellos basados ​​en un complemento de Babel. Las instrucciones sobre cómo usarlos están disponibles en el repositorio. Aquí, usaremos el complemento webpack.

const Style9Plugin = require('style9/webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      // This will transform the style9 calls
      {
        test: /.(tsx|ts|js|mjs|jsx)$/,
        use: Style9Plugin.loader
      },
      // This is part of the normal Webpack CSS extraction
      {
        test: /.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  },
  plugins: [
    // This will sort and remove duplicate declarations in the final CSS file
    new Style9Plugin(),
    // This is part of the normal Webpack CSS extraction
    new MiniCssExtractPlugin()
  ]
};

Definición de estilos

La sintaxis para crear estilos se parece mucho a la de otras bibliotecas. Empezamos llamando style9.create con objetos de estilos:

import style9 from 'style9';

const styles = style9.create({
  button: {
    padding: 0,
    color: 'rebeccapurple'
  },
  padding: {
    padding: 12
  },
  icon: {
    width: 24,
    height: 24
  }
});

Debido a que todas las declaraciones darán como resultado clases atómicas, abreviaturas como flex: 1 y background: blue no funcionará, ya que establecen múltiples propiedades. Las propiedades que se pueden ampliar, como padding, margin, overflow, etc. se convertirán automáticamente a sus variantes manuscritas. Si usa TypeScript, obtendrá un error cuando use propiedades no admitidas.

Resolviendo estilos

Para generar un nombre de clase, ahora podemos llamar a la función devuelta por style9.create. Acepta como argumentos las claves de los estilos que queremos usar:

const className = styles('button');

La función funciona de tal manera que los estilos de la derecha tienen prioridad y se fusionarán con los estilos de la izquierda, como Object.assign. Lo siguiente daría como resultado un elemento con un relleno de 12px y con rebeccapurple texto.

const className = styles('button', 'padding');

Podemos aplicar estilos condicionalmente usando cualquiera de los siguientes formatos:

// logical AND
styles('button', hasPadding && 'padding');
// ternary
styles('button', isGreen ? 'green' : 'red');
// object of booleans
styles({
  button: true,
  green: isGreen,
  padding: hasPadding
});

Estas llamadas a funciones se eliminarán durante la compilación y se reemplazarán con la concatenación directa de cadenas. La primera línea del código anterior será reemplazada por algo como 'c1r9f2e5 ' + hasPadding ? 'cu2kwdz ' : ''. Ningún tiempo de ejecución se queda atrás.

Combinando estilos

Podemos extender un objeto de estilo accediendo a él con un nombre de propiedad y pasándolo a style9.

const styles = style9.create({ blue: { color: 'blue; } });
const otherStyles = style9.create({ red: { color: 'red; } });

// will be red
const className = style9(styles.blue, otherStyles.red);

Al igual que con la llamada de función, los estilos de la derecha tienen prioridad. En este caso, sin embargo, el nombre de la clase no se puede resolver estáticamente. En su lugar, los valores de propiedad serán reemplazados por clases y se unirán en tiempo de ejecución. Las propiedades se agregan al archivo CSS como antes.

Resumen

Los beneficios de CSS-in-JS son muy reales. Dicho esto, estamos imponiendo un costo de rendimiento al incorporar estilos en nuestro código. Al extraer los valores durante el tiempo de compilación, podemos tener lo mejor de ambos mundos. Nos beneficiamos de la ubicación conjunta de nuestros estilos con nuestro marcado y la capacidad de usar la infraestructura de JavaScript existente, al mismo tiempo que podemos generar hojas de estilo óptimas.

Si style9 le parece interesante, eche un vistazo al repositorio y pruébelo. Y si tiene alguna pregunta, no dude en abrir un problema o ponerse en contacto.

Agradecimientos

Gracias a Giuseppe Gurgone por su trabajo en hojas de estilo y dss, Nicolas Gallagher por react-native-web, Satyajit Sahoo y todos en Callstack por linaria, Christopher Chedeau, Sebastian McKenzie, Frank Yan, Ashley Watkins, Naman Goel y todos los demás. que trabajó en stylex en Facebook por tener la amabilidad de compartir sus lecciones públicamente. Y cualquier otra persona a la que he echado de menos.

Enlaces

  • johanholmerin/estilo9
  • Construyendo el nuevo facebook.com con React, GraphQL y Relay – 30 de abril de 2019
  • Construyendo el nuevo Facebook con React y Relay | Frank Yan – 30 de octubre de 2019
  • Reconstrucción de la pila tecnológica para un nuevo Facebook.com: 8 de mayo de 2020
  • johanholmerin/style9-components.macro: API de componentes con estilo para style9 – experimental
(Visited 9 times, 1 visits today)