Skip to content

Modo perezoso

Por defecto, EffCSS genera CSS de forma inmediata: las reglas de la hoja de estilos se escriben en el CSSOM en cuanto se llama a una utilidad. En el modo diferido, la generación se pospone: el CSS se añade a la hoja de estilos solo cuando se utiliza el resolvedor generado (ya sea mediante llamada o conversión a cadena).

El modo diferido está disponible en dos variantes, para que puedas elegir el nivel de control que necesitas:

VarianteActivadorÁmbito
ControladoUtilidades lazy* opcionalesPor utilidad, siempre diferido
A nivel de bibliotecaconfigure({ lazy: true })Cada utilidad generadora que devuelve un resolvedor

Funcionan de forma independiente y se pueden combinar.

1. Controlado: utilidades lazy*

Estas utilidades son siempre diferidas, independientemente de cualquier configuración global. Cada llamada devuelve un resolvedor de funciones. No se genera nada hasta que:

  • llames al resolvedor — fn() (o fn(...args)),
  • lo conviertas a cadena — ${fn}` o String(fn).

El contenido de la regla se puede pasar como un objeto o como una función que devuelve el objeto. Una función se evalúa de forma diferida, en el primer calentamiento.

UtilidadDevuelveGenera
lazyClassName(regla) (o className.lazy(regla))() => string (nombre de la clase)una regla de clase anónima
lazyAttribute(regla) (o attribute.lazy(regla))() => object ({ 'data-…': '' })una regla de atributo anónima
lazyClassNames(gen) (o classNames.lazy(gen))resolvedor de selectoresuna hoja de estilo de selector de clase
lazyAttributes(gen) (o attributes.lazy(gen))resolvedor de selectoresuna hoja de estilo de selector de atributo
lazyCustomStyles(gen) (o customStyles.lazy(gen))resolvedor de selectoresuna hoja de estilo personalizada

Antes - hacer inmediatamente

ts
import { className, attribute, classNames } from 'effcss';

// CSS is written into the shared stylesheet right here
const centerCls = className({ margin: 'auto' });
const markerAttr = attribute({ fontWeight: 'bold' });
const utils = classNames<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' },
        [w.m]: { width: '16px' }
    };
});

Cada llamada genera una regla inmediatamente, incluso si el resultado nunca se utiliza en la página.

Después — controlado perezoso

ts
import { lazyClassName, lazyAttribute, lazyClassNames } from 'effcss';

// nothing is generated at creation time
const centerCls = className.lazy({ margin: 'auto' });
const markerAttr = attribute.lazy({ fontWeight: 'bold' });
const utils = classNames.lazy<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' },
        [w.m]: { width: '16px' }
    };
});

// ... later, where the value is actually consumed:
<div className={centerCls()} {...markerAttr()}>   // generates the anonymous rules
<div className={utils({ w: 'm' })} />             // generates the stylesheet

Tenga en cuenta que todos los manejadores perezosos, incluso lazyClassName (className.lazy) y lazyAttribute (attribute.lazy), devuelven funciones. Para los resolutores perezosos de reglas individuales, esto ofrece una ventaja adicional: convertir dicho resolutor a una cadena devuelve el selector correcto, que puede utilizarse en otros estilos:

ts
const divider = className.lazy({
    width: '100%',
    height: '1px'
});

const layout = classNames.lazy<Layout>((selectors) => ({
    [selectors.row]: {
        display: 'flex'
    },
    // `divider` coerce to its real `.class` selector
    // when `layout` will be used at the first time
    [`& ${divider}`]: {
        background: 'red'
    }
}));

Además, estas funciones pueden aceptar no solo un objeto, sino también un generador:

ts
const divider = className.lazy(() => {
    // you can create other global rules inside
    // so that they are created the first time className is used
    const width = variable('100%');
    return {
        width: width(),
        height: '1px',
        '&:hover': {
            [width]: '50%'
        }
    };
});

Importante: className / attribute devuelve un valor que no es una función (string / objeto); no son perezosos y no están involucrados aquí.

2. A nivel de biblioteca — configure({ lazy: true })

configure({ lazy: true }) cambia, sobre la marcha, toda utilidad generadora que devuelve un solucionador de funciones a su versión perezosa:

variable, variables, animation, animations, layer, layers, font, fonts, classNames, attributes, customStyles.

Sigues escribiendo la misma API; no es necesario usar nombres de carga diferida. Cada una de estas utilidades ahora pospone la generación hasta que se utiliza su resultado.

Las funciones className y attribute no se ven afectadas: devuelven valores simples (string / objeto) en lugar de resolutores, por lo que siguen generándose inmediatamente.

Antes - predeterminado (ansioso)

ts
import { variable, animation, classNames } from 'effcss';

const shadowColor = variable('#58666d');
const spin = animation({ to: { transform: 'rotate(360deg)' } });

const utils = classNames<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' }
    };
});

Después — configure({ lazy: true })

ts
import { configure, variable, animation, classNames } from 'effcss';

configure({ lazy: true });

// same API, different timing
const shadowColor = variable('#58666d');
const spin = animation({ to: { transform: 'rotate(360deg)' } });
// nothing is written yet

const utils = classNames.lazy<Utils>((selectors) => {
    const { w } = selectors;
    return {
        [w.s]: { width: '12px' }
    };
});
// nothing is written yet

// CSS is produced only on first real use:
`${shadowColor()} or ${shadowColor}`
`${spin()} or ${spin}`
utils({ w: 's' })

Para utilidades múltiples (variables, animaciones, capas, fuentes, etc.), todo el lote se prepara conjuntamente: al modificar cualquier resolvedor, se genera el conjunto completo, manteniendo el orden determinista para la hidratación del renderizado del lado del servidor (SSR).

Notas sobre el comportamiento

  • Activadores de precalentamiento: un resolvedor se prepara al llamarlo o mediante conversión de cadena. Simplemente mantenerlo en espera (o llamar a .get() / .set() para variables) no genera CSS.

  • variable().get() / .set(): antes de prepararse, get() devuelve '' y set() no tiene efecto; se activan solo después de que el resolvedor se haya preparado.

  • update(): en modo diferido, no modifica las variables que aún no se han creado.

  • Hidratación SSR: el orden de generación es determinista (contadores internos compartidos), por lo que el servidor y el cliente generan selectores idénticos siempre que calienten los resolvedores en el mismo orden.

  • Eventos subscribe: los EffCSSEvent se emiten en el momento de la generación real (calentamiento del resolvedor), no cuando se llama inicialmente a la utilidad.

Elegir entre las dos opciones

  • Utilice las utilidades `lazy controladas* cuando desee la carga diferida solo para reglas específicas y mantenga el resto en modo "eager", o cuando desee garantizar la carga diferida independientemente de la configuración general de la aplicación.

  • Utilice configure({ lazy: true }) cuando desee un comportamiento general de solo lo que se usa en toda la biblioteca sin modificar el código, por ejemplo, combinado con vite-plugin-effcss para enviar solo el CSS que se renderiza realmente.

Publicado bajo la Licencia Apache 2.0