w3schools scss mixin imports how define css node.js express sass node-sass

scss - Inyectando variables durante la compilación SASS con Nodo



sass-- watch (3)

En una aplicación en la que estoy trabajando, tengo que compilar dinámicamente SASS antes de renderizar en el cliente (el sistema de almacenamiento en caché viene, no te preocupes) Actualmente estoy usando node-sass y todo está funcionando muy bien.

Aquí es en lo que estoy trabajando hasta ahora. Otro código específico del proyecto ha sido eliminado por brevedad:

var sass = require(''node-sass''), autoprefixer = require(''autoprefixer-core''), vars = require(''postcss-simple-vars''), postcss = require(''postcss''), function compileCSS() { var result = sass.renderSync({ file: ''path/to/style.scss'' }); return postcss([autoprefixer]).process(result.css.toString()).css; }

El problema es que ahora necesito pasar datos dinámicos de Node y compilarlos como una variable SASS normal. Inicialmente intenté usar PostCSS , porque noté que la inyección de variables era algo que podía hacer . Desafortunadamente, eso no funcionó. PostCSS comienza después de la fase de compilación, que falla miserablemente en este punto.

Luego, traté de usar plantillas de underscore para intentar sobrescribir usando el importer() node-sass '' importer() :

var result = sass.renderSync({ file: ''path/to/style.scss'', importer: function(url, prev, done) { var content = fs.readFileSync(partial_path), partial = _.template(content.toString()); return { contents: partial({ test: ''test'' }) }; } });

Lo que resultó en el siguiente error:

Error: error reading values after :

Obviamente a SASS no le gustó la sintaxis variable del guión bajo ...

TL; DR

¿Cómo puedo pasar las variables dinámicas a SASS desde mi aplicación Node?

Información Adicional

  1. Mi equipo y yo no somos completamente adversos a cambiar a algo como Stylus ; Sin embargo, hemos logrado un progreso significativo hasta el momento y sería un dolor.

Estaba resolviendo un problema similar aunque no en Node sino en Java. Se me exigió que representara las variables SASS de la base de datos para generar el tema del sitio web, en función del cliente que acceda al sitio web.

Exploré algunas soluciones y encontré este servicio de terceros https://www.grooveui.com . Ofrece una solución de lenguaje independiente para resolver este problema.


Me encontré en una situación muy similar. Teníamos una gran cantidad de SASS que ahora necesitaba aceptar valores / variables dinámicos para ser utilizados en todo (como variables). Originalmente seguí la ruta de escribir directorios / archivos temporales y esencialmente crear un "punto de entrada de proxy" que crearía un proxy_entry.scss y variables.scss y arrancaría el entry.scss real con las variables SASS previstas declaradas. Esto funcionó bien y logró los resultados deseados, pero se sintió un poco complicado ...

Resulta que hay una solución mucho más simple disponible gracias a la opción options.data node-sass . Esto acepta una "cadena SASS para ser evaluada".

Tipo: Cadena Valor predeterminado: nulo Especial: se debe especificar el archivo o los datos

Una cadena para pasar a libsass para hacer. Se recomienda que use includePaths junto con esto para que libsass pueda encontrar archivos cuando use la directiva @import.

Esto eliminó completamente la necesidad de escribir / administrar todos los directorios y archivos temporales.

Visual TL; DR

La solución se reduce a algo como esto

1.) Definir sassOptions como de costumbre.

var sassOptionsDefaults = { includePaths: [ ''some/include/path'' ], outputStyle: ''compressed'' };

2.) Escriba la "cadena SASS dinámica" para options.data

var dataString = sassGenerator.sassVariables(variables) + sassGenerator.sassImport(scssEntry); var sassOptions = _.assign({}, sassOptionsDefaults, { data: dataString });

3.) Evaluar el SASS como de costumbre.

var sass = require(''node-sass''); sass.render(sassOptions, function (err, result) { return (err) ? handleError(err); : handleSuccess(result.css.toString()); });

Nota: esto es asumiendo que su entry.scss importa algunas variables.scss que definen las variables como "predeterminadas".

// variables.scss $someColor: blue !default; $someFontSize: 13px !default; // entry.scss @import ''variables''; .some-selector { color: $someColor; font-size: $someFontSize; }

Uniendo todo como ejemplo

var sass = require(''node-sass''); // 1.) Define sassOptions as usual var sassOptionsDefaults = { includePaths: [ ''some/include/path'' ], outputStyle: ''compressed'' }; function dynamicSass(scssEntry, variables, handleSuccess, handleError) { // 2.) Dynamically create "SASS variable declarations" // then import the "actual entry.scss file". // dataString is just "SASS" to be evaluated before // the actual entry.scss is imported. var dataString = sassGenerator.sassVariables(variables) + sassGenerator.sassImport(scssEntry); var sassOptions = _.assign({}, sassOptionsDefaults, { data: dataString }); // 3.) render sass as usual sass.render(sassOptions, function (err, result) { return (err) ? handleError(err); : handleSuccess(result.css.toString()); }); } // Example usage. dynamicSass(''some/path/entry.scss'', { ''someColor'': ''red'', ''someFontSize'': ''18px'' }, someSuccessFn, someErrorFn);

Donde las funciones "sassGenerator" podrían verse algo así como

function sassVariable(name, value) { return "$" + name + ": " + value + ";"; } function sassVariables(variablesObj) { return Object.keys(variablesObj).map(function (name) { return sassVariable(name, variablesObj[name]); }).join(''/n'') } function sassImport(path) { return "@import ''" + path + "'';"; }

Esto le permite escribir su SASS como lo hizo antes, utilizando las variables SASS en cualquier lugar que se necesiten . Tampoco lo relaciona con ninguna "implementación de Sass dinámica especial" (es decir, esto evita el uso de "subrayado / lodash plantillas en sus archivos .scss ). También significa que puede aprovechar las características de IDE, linting, etc ... de la misma manera, ya que acaba de volver a escribir SASS regular .

Además, se traduce muy bien a los usos de non-node / http / compile-on-the-fly tales como entry.scss de múltiples variaciones de entry.scss dados conjuntos de valores múltiples a través de Gulp, etc.

Espero que esto te ayude a salir de @ChrisWright (y otros)! Sé que tuve problemas para encontrar información sobre el tema y me imagino que este es un caso de uso bastante común (querer pasar valores dinámicos a SASS desde una Base de datos, configuración, parámetros HTTP, etc.).


Pude resolver esto después de que envolví mi cabeza alrededor del método de importer() node-sass. Mi solución incluía plantillas de subrayado y lectura manual de los archivos a medida que se introducen. No es la solución más elegante y eficiente, pero solo se ejecuta una vez por página generada. Después de eso, los archivos se minimizan y se almacenan en caché para futuras solicitudes.

// Other none-sass render parameters omitted for brevity importer: function (url, prev, done) { // Manually read each partial file as it''s encountered fs.readFile(url, function (err, result) { if (err) { // If there is an error reading the file, call done() with // no content to avoid a crash return done({ contents: '''' }); } // Create an underscore template out of the partial var partial = _.template(result.toString()); // Compile template and return its contents to node-sass for // compilation with the rest of the SCSS partials done({ contents: partial({ data: YOUR_DATA_OBJECT }) }); }); }

Al usar esta solución, podemos hacer referencia a la sintaxis de las variables de subrayado normales dentro de nuestros parciales de SCSS. Como ejemplo:

body { color: <%= data.colour %>; }