Compilador

El Compilador es el núcleo para generar CSS con Stylify. Esta herramienta genera CSS y reescribe (mangles) selectores. También cuando necesitas añadir Variables, Componentes, Macros personalizadas y etc, lo haces en una configuración del Compilador.

Sintaxis

La sintaxis es similar a CSS propiedad:valor con algunas diferencias:

  • Usar _ (un guión bajo) para un espacio y ^ (un sombrero) para una comilla.
  • El patrón sintáctico por defecto es <pantalla>:<pseudoclases>:<propiedad>:<valor>. Las pantallas y las pseudoclases son opcionales.
  • Las pantallas pueden combinarse mediante operandos lógicos:
    • AND lógico: &&
    • OR lógico: ||
color:blue => color azul
hover:color:blue => color azul después de hover
lg:color:blue => color azul desde la pantalla seleccionada
lg:hover:color:blue => color azul después de pasar el cursor desde la pantalla seleccionada

lg&&dark:color:red => pantalla grande y preferir esquema de color oscuro
minw740px||landscape:color:blue => para anchura mínima u horizontal

Configuración del compilador

dev

Si dev se establece en true, el CSS generado contendrá nuevas líneas y espacios para ser más legible, los selectores en el CSS generado no serán manipulados y si falta alguna variable, sólo se mostrará una advertencia en la consola.

const compilerConfig = {
	dev: true
};

macros

Las macros se utilizan para hacer coincidir selectores y generar CSS de acuerdo con la coincidencia. La clave dentro del objeto puede ser una cadena o una expresión regular.

Cada selector coincidente es automáticamente manipulado si está habilitado: color:rgb(255,255,255) => ab.

const compilerConfig = {
	macros: {
		'color:(\\S+?)': (match) => {
			// color:blue => creará => color: blue
			return {'color': match.getCapture(0)}
		},
	},
};

Uso:

<span class="color:red"></span>
<div class="color:#000"></span>
<div class="color:rgb(255,255,255)"></span>

selectorsPrefix

Esta opción permite establecer, por ejemplo, el prefijo u- (como utilidad). Este prefijo se unirá a las macros durante la búsqueda.

Cuando defina dicho prefijo, debe utilizarlo en cualquier lugar (selectores personalizados, componentes, utilidades). De lo contrario, los selectores no coincidirán ni se generarán.

Gracias a esta característica puedes usar Stylify dentro de tu aplicación existente sin colisión con selectores ya existentes.

const compilerConfig = {
	selectorsPrefix: 'u-'
};

Y en el código

<div class="
	u-color:blue
	hover:u-color:red
	[a]{u-color:blue}
"></div>

mangleSelectors

Si la opción mangle selectors está en true, los selectores en CSS serán mangled de largos a cortos.

Esto sólo configura el Resultado de Compilación para que genere selectores CSS minificados. Para reescribir los selectores en los archivos, es necesario llamar al método compiler.rewriteSelectors(content).

El método rewriteSelectors se ejecuta automáticamente dentro de los paquetes Unplugin, Bundler, Astro, Nuxt y Nuxt Module. Usted tiene que llamarlo sólo, si desea trabajar con el compilador directamente.

const compilerConfig = {
	mangleSelectors: true
};
const compiler = new Compiler(config);

compiler.rewriteSelectors(content);

mangledSelectorsPrefix

Este prefijo se añade antes de todos los selectores mangled. Puede utilizar cualquier carácter no numérico, por ejemplo _ (un guión bajo).

Esta característica evita la colisión de los selectores manipulados con los que ya tenga en su aplicación. Utilícela sólo cuando exista tal colisión.

const compilerConfig = {
	mangledSelectorsPrefix: '_'
};
<div class="color:blue"></div>

<!-- Con configuración -->
<div class="_a"></div>

<!-- Sin configuración -->
<div class="a"></div>

variables

Las variables se pueden usar en un selector o acceder a ellas dentro de una macro.

const compilerConfig = {
	variables: {
		blue: '#01befe',
		shadow: '0 8px 32px -8px rgb(0, 0, 0, 0.2)',
		// Cuando la variable es un objeto, Stylify CSS intenta encontrarle una pantalla
		// Puedes usar cualquier pantalla que hayas definido en las pantallas
		dark: { blue: 'lightblue' },
		md: { fontSize: 24px },
		'minw640px': { fontSize: 32px },
		// Cuando no se encuentra la pantalla, se vuelve a un selector personalizado aleatorio
		'.dark': { blue: 'lightblue' },
		':root[data-theme="dark"]': { blue: 'lightblue' }
	},
	// Si desea desactivar las variables CSS, establezca esta opción en false
	cssVariablesEnabled: true,
	// Por defecto, las variables se inyectan automáticamente en el CSS generado como variables CSS.
	// Puedes cambiar este comportamiento configurando la opción de abajo como false
	injectVariablesIntoCss: true
};

Uso:

<span class="color:$blue"></span>

externalVariables

En caso de que tengas algunas variables CSS definidas en otro lugar que no sea la configuración de Stylify, puedes marcarlas y añadirlas como externas.

Las variables externas no pueden ser usadas dentro de helpers porque su valor no puede ser accedido y procesado.
const compilerConfig = {
	externalVariables: [
		// Comprobación de cadena simple
		'some-color',
		// Definir callback para especificar una comprobación más flexible.
		// Esto marcará, por ejemplo, cada variable que empiece por md-
		// como externa.
		(variable) => variable.startsWith('md-') ? true : undefined
	],
	// Si tienes muchas variables externas y no quieres molestarte en mapearlas,
	// puedes cambiar el nivel de advertencia
	// 'silent' => desactiva completamente la advertencia
	// 'warn' => es por defecto para desarrollo
	// 'error' => por defecto para producción
	undefinedVariableWarningLevel: 'silent'
};

Uso:

<span class="
	color:$some-color
	background:$md-sys-color-primary
	border-color:$md-sys-color-tertiary
"></span>

keyframes

Los keyframes en Stylify CSS se definen con la misma sintaxis que en el CSS.

Los keyfames también se pueden definir dentro de un comentario dentro de un archivo usando opciones de contenido.

const compilerConfig = {
	keyframes: {
		fadeIn: 'from { opacity: 0; } to { opacity: 1; }',
		fadeOut: 'from { opacity: 1; } to { opacity: 0; }',
		shadowPulse: `
			from { box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.2); }
			to { box-shadow: 0 0 0 20px rgba(0, 0, 0, 0); }
		`
	}
};
<span class="animation:fadeIn_2s_infinite">Desvanecer</span>
<span class="animation:fadeOut_2s_infinite">Desvanecimiento</span>
<span class="animation:shadowPulse_2s_infinite">Pulso de sombra</span>

screens

Las pantallas se utilizan para generar consultas de medios. La clave puede ser una cadena o una expresión regular. Puede utilizar [pantallas] predefinidas (/es/docs/stylify/native-preset#screens) o definir las suyas propias.

Las pantallas pueden combinarse utilizando operandos lógicos:

  • AND lógico: &&
  • OR lógico: ||
const compilerConfig = {
	screens: {
		'sm': '(min-width: 400px)',
		// Las pantallas también pueden ser funciones
		// Eso te permite hacer una pantalla lo más flexible posible
		'minw\\w+': (screen) => `(min-width: ${screen.fullMatch.replace('minw', '')})`
	}
};

Uso:

<span class="sm:color:darkred"></span>
<div class="minw640px:color:$blue"></span>
<div class="minw80rem:color:darkgreen"></span>

components

Los componentes pueden disminuir la cantidad de selectores en una plantilla. Se pueden definir en el fichero donde se usan o en el config. Cuando se definen usando content-option, se espera el objeto javascript sin los corchetes circundantes. Cuando se define un componente, también se puede utilizar sintaxis anidada

Los componentes también pueden definirse directamente en archivos utilizando opciones de contenido.

Cuando se define un componente o macro como link este selector puede tener una colisión en producción con selector como sidebar-link, al manipular selectores. Este selector será reemplazado por a (para enlace) y barra lateral-a (para sección). Puede evitar este comportamiento configurando sidebar-section en la opción ignoredAreas.
const compilerConfig = {
	components: {
		// selector => dependencias
		'button': 'padding:4px background:black color:white hover:background:grey',
		'container': `
			max-width:1024px
			margin:0_auto
			md:max-width:1280px
		`,
		// Puedes definir múltiples componentes en una clave, sólo tienes que separarlos por "," (coma)
		'wrapper, footer': 'padding:24px',
		// Cuando un componente se define varias veces, los selectores se fusionan
		// Cuando se define selectorsChain se aplica el último
		'wrapper': 'margin-top:24px',
		'button--big': `
			&.btn {
				font-size:48px
			}
		`,
		// Componentes dinámicos
		// Cuando la función tiene un callback, acepta coincidencias de expresión regular
		// variables, helpers y si es dev environment.
		// De esta forma puedes definir componentes que devuelvan selectores basados en coincidencias
		// de la expresión regular.
		'title(?:--(\\S+))?': ({ matches, variables, helpers, dev }) => {
			const color = matches[1] ?? '#000';
			return `font-size:24px${color ? ` color:${color}` : ''}`;
		},
	}
};

Uso:

<span class="button"></span>
<div class="container"></div>
<!-- Componentes dinámicos -->
<div class="title"></div>
<div class="title--#06f">
<div class="title--$red">

customSelectors

Los selectores personalizados te permiten escribir selectores CSS para elementos. Cuando se configura una pseudoclase para un elemento directo, se puede utilizar la pseudoclase directamente. Cuando el selector no es directo, entonces la pseudo clase debe estar en el selector y no en el selector CSS de Stylify. Echa un vistazo a los ejemplos.

Los selectores personalizados también se pueden definir directamente en los archivos usando opciones de contenido.

const compilerConfig = {
	customSelectors: {
		// selector => dependencias
		'article': 'font-size:16px line-height:28px color:#222',
		'article h1, article h2': 'color:blue',
		// Para selectores indirectos con pseudoclase como `div > button`, `article a`
		'article a:hover': 'color:blue'
		'article a:hover i': 'color:white'
		// Para selectores directos con pseudoclase como a, input o a.button y a.link
		'a': 'color:green hover:color:blue',
		'a.link': 'color:green hover:color:red'
	}
};

Uso:

<article></article>

Sintaxis anidada para selectores personalizados.

Puedes anidar selectores usando una sintaxis similar a SCSS. Para crear el selector es igual que en CSS. Para referirse al nivel superior utilice el carácter &. Para simplificar las cosas, la única función es anidar y encadenar. La sintaxis es la misma para las “opciones de contenido”. Las pseudo clases como :hover funcionan igual que en el ejemplo anterior. El siguiente ejemplo generará lo siguiente:

  • header { width:800px }
  • header nav { font-size:14px }
  • header.fixed {}
  • .docs header { background:blue }
  • header h1, header h2 { font-family:arial }
const compilerConfig = {
	customSelectors: {
		'header': `
			width:800px
			nav {
				font-size:14px
			}
			&.fixed {
				position:fixed
			}
			.docs & { background:blue }
			h1, h2 { font-family:arial }
		`
	}
}

Los selectores personalizados también se pueden escribir directamente en los atributos de clase. La sintaxis es la siguiente [selector]{macros}. En lugar de un espacio utilice el guión bajo _. Para una comilla, utilice ^. Y para dividir diferentes macros utilice ;. El siguiente ejemplo generará lo siguiente:

  • .docs [.docs_&]{font-size:14px;color:#222} {font-size:14px; color:#222}
  • [h1,h2]{margin-top:0} h1, [h1,h2]{margin-top:0} h2 { margin-top:0 }

Para pseudoclases:

  • [a::after]{content:^Hola_Mundo^} a::after {content:'Hola Mundo'}
  • [a]{hover:color:steelblue} a:hover {color:steelblue}
  • [a:hover]{color:stelblue} a:hover {color:stelblue}
  • [&:hover_a]{color:stelblue}:hover a {color:stelblue}
<article class="
	[.docs_&]{font-size:14px;color:#222}
	[h1,h2]{margin-top:0}

	[a]{hover:color:steelblue}
	[a:hover]{color:stelblue}
	[&:hover_a]{color:stelblue}
"></article>

helpers

Los helpers son funciones que pueden ser llamadas cuando un selector coincide y sus propiedades están siendo generadas.

const compilerConfig = {
	helpers: {
		shortcut(value) {
			const shortcuts = {
				'bgc': 'background-color',
				'zi': 'z-index'
			};

			return value in shortcuts ? shortcuts[value] : value;
		},
		joinText(...texts) => '"' + texts.join(' ') + '"'
	},
	macros: {
		'(bgc|zi):(\\S+?)'(match) {
			const property = this.helpers.shortcut(match.getCapture(0));
			return {[property]: match.getCapture(1)}
		}
	}
}

Uso:

<div class="
	zi:2 bgc:red
	color:lighten(#000,10)
	content:joinText(^Custom^,^Long_Text^)
"></div>

selectorsAreas

En caso de que quieras reescribir selectores en cualquier atributo de clase específico de framework, debes definir ese atributo para que coincida. Por defecto Stylify CSS soporta algunas sintaxis de HTML, Vue, React, Lit, AlpineJS, Svelte, Astro, Symfony y Nette. En caso de que alguno de los atributos de clase no coincida, añade la opción selectorsAreas con una expresión regular para que coincida.

const compilerConfig = {
	selectorsAreas: [
		// Vue.js
		/(?:^|\s+)(?:v-bind)?:class="([^"]+)"/,
		// React
		/(?:^|\s+)className="([^"]+)"/
	]
};

ignoredAreas

En caso de que necesites marcar un código para que sea ignorado durante la compilación, puedes usar áreas ignoradas.

stylify-ignore y stylify-runtime-ignore son por defecto áreas que puedes usar para eliminar contenido de la compilación.

También se ignoran los siguientes elementos (sólo sin atributos): code, head, pre, script, style.

Tenga en cuenta que la coincidencia de etiquetas o áreas usando expresiones regulares no es fiable en algunas situaciones, por lo tanto intente usar stylify-ignore ya que es la opción más fiable.

Uso

<!-- stylify-ignore -->
Todo lo que esté dentro será ignorado
<div class="color:red"></div>
<!-- /stylify-ignore -->

pregenerate

La opción pregenerate permite añadir algún contenido en el proceso de compilación.

const compilerConfig = {
	pregenerate: 'color:red color:blue width:100%'
};

contentOptionsProcessors

Algunas opciones de configuración pueden definirse directamente en un fichero utilizando content options. Es bueno guardar la definición por ejemplo de un componente con su HTML. Cada opción de contenido, incluso cuando se define en un archivo, se registra globalmente. Tampoco tiene ningún tipo de alcance. Así que si defines un componente, como un botón, puede ser usado en cualquier parte de la aplicación.

Las opciones de contenido pueden ser definidas en cualquier lugar dentro de un archivo como este:

stylify-<nombre de la opción>
  Contenido de la opción de contenido
/stylify-<nombre de la opción>

La mejor manera es definir las opciones de contenido dentro de un comentario multilínea, para que no sea visible en la página.

Utiliza el estilo de comentario que sea válido para el tipo de archivo donde definas el componente.
<!--

// Components espera un objeto javascript válido como valor sin corchetes alrededor
stylify-components
	button: `font-size:24px padding:4px`,
	'button--big': `
		&.btn {
			font-size:48px
		}
	`
/stylify-components

// Variables espera un objeto javascript válido como valor sin los corchetes circundantes
stylify-variables
	blue: `#01befe`
/stylify-variables

// Keyframes espera un objeto javascript válido como valor sin corchetes alrededor
stylify-keyframes
	fadeIn: 'from { opacity: 0; } to { opacity: 1; }',
	fadeOut: 'from { opacity: 1; } to { opacity: 0; }',
	shadowPulse: `
		from { box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.2); }
		to { box-shadow: 0 0 0 20px rgba(0, 0, 0, 0); }
	`
/stylify-keyframes


// Los selectores personalizados esperan un objeto javascript válido como valor sin los corchetes circundantes
stylify-customSelectors
	article: `font-size:24px`
/stylify-customSelectors

// Pregenerate espera una cadena
stylify-pregenerate
	border-top:1px_solid_#444
/stylify-pregenerate

// Screens espera un objeto javascript válido como valor sin los corchetes circundantes
stylify-screens
	'testScreen': '(min-width: 123px)',
	'dynamic\\w+': (screen) => `(max-width: ${screen.fullMatch.replace('dynamic', '')})`
/stylify-screens
-->

Añadir procesador de opciones de contenido personalizado

import { hooks } from '@stylify/stylify'

// Puedes usar el compilador de Stylify para obtener cualquier opción
hooks.addListener('compiler:processContentOption:myOption', ({
	contentOptions,
	option,
	value
}) => {

});

Resultado de la compilación

Resultado de la compilación puede ser creado o configurado y pasado en el compilador como un segundo argumento. Mediante este enfoque, puede cambiar el comportamiento de compilación y ampliar la funcionalidad.

Ten en cuenta que si modificas el resultado de la compilación o creas uno nuevo con una configuración incorrecta, puedes romper todo el proceso de compilación.
const compilationResult = new CompilationResult({
	// Todas las opciones son opcionales
	dev: false,
	// Si reconfigurable se establece en false, la configuración no cambiará
	reconfigurable: false,
	// Esta función se encarga de ordenar las pantallas antes de generar el CSS.
	// El argumento es un tipo Map y la función también debe devolver un tipo Map.
	screensSortingFunction: (screensList) => { return screensList },
	// Si mangle selectors es true, los selectores dentro del CSS serán manhled
	mangleSelectors: false,
});

Registro CSS

Sólo se puede acceder al registro CSS a través de un hook compilationResult:configureCssRecord. El registro CSS es responsable de mantener el árbol CSS y cómo se unen, gestionan y etc los selectores.

hooks.addListener('compilationResult:configureCssRecord', ({cssRecord}) => {
	// ...
});

Ganchos

Stylify tiene un sistema hookable que permite modificar extender la funcionalidad.

  • compiler:beforeMacrosProcessed: Antes de que el contenido sea procesado y las macros coincidan.
  • compiler:afterMacrosProcessed: Justo después del beforeMacrosProcessed.
  • compiler:compilationResultConfigured: Se activa cuando el resultado de la compilación está listo
  • compiler:newMacroMatch: Este hook se dispara cuando una macro coincide dentro del contenido
  • compiler:processContentOption:[option]: Se activa al procesar la opción de contenido. El [option] debe ser reemplazado por el nombre de la opción de contenido como customOption si desea procesar sus propias opciones
  • compilationResult:configureCssRecord: Este hook es llamado cuando se crea un registro CSS. Puede, por ejemplo, establecer el ámbito
  • cssRecord:addProperty: Se llama justo antes de que se añada el CSS propiedad:valor.
  • cssRecord:cssGenerated: Se activa cuando se genera el CSS
import { hooks } from '@stylify/stylify';

hooks.addListener('hoook:name', (options) => {});

Proceso de compilación personalizado

import { Compiler } from '@stylify/stylify';

const content = '<div class="color:blue"></div>';

const compiler = new Compiler();
const compilationResult = compiler.compile(content);
const css = compilationResult.generateCss();
// Si se establece el tercer parámetro y si es true (por defecto) reescribe los selectores
// sólo en las áreas definidas en selectorsAreas y no en todo el contenido
const mangledContent = compiler.rewriteSelectors(content, compilationResult, true);