使用节点在SASS编译期间注入variables

在我正在工作的应用程序中,我必须在客户端呈现之前dynamic编译SASS(caching系统即将到来,不用担心)。 目前我正在使用节点sass ,一切都很好。

这是我到目前为止的工作。 其他项目特定的代码已被删除,以简洁起见:

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; } 

现在我需要从节点传递dynamic数据,并像普通的SASSvariables那样编译。 最初我尝试使用PostCSS ,因为我注意到,variables注入是它可以做的事情 。 不幸的是,这并没有奏效。 PostCSS在编译阶段之后就开始了,这个失败很惨。

接下来,我尝试使用下划线模板尝试使用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' }) }; } }); 

导致以下错误:

 Error: error reading values after : 

SASS显然不喜欢下划线的variables语法..


TL; DR

我如何从Node应用程序中将dynamicvariables传递给SASS?


附加信息

  1. 我和我的团队并不完全不喜欢手写笔 , 但是,到目前为止,我们已经取得了重大进展,这将是一个痛苦。

我发现自己的情况非常相似。 我们有很多现有的SASS现在需要接受dynamic值/variables(作为variables)。 我最初写了临时目录/文件的路线,本质上创build了一个“代理入口点”,这将创build一个proxy_entry.scssvariables.scss并引导实际的entry.scss声明SASSvariables。 这工作得很好,取得了理想的结果,但感觉有点过于复杂…

事实certificate,有一个更简单的解决scheme可用得益于节点sass的options.data选项。 这接受“要评估的SASSstring”。

types:string默认值:null特殊:必须指定文件或数据

一个string传递给libsass来渲染。 build议您将includePaths与此结合使用,以便libsass在使用@import指令时可以find文件。

这完全消除了编写/pipe理所有临时目录和文件的需要。

Visual TL; DR

SASS中带有节点的动态变量

解决scheme归结为这样的事情

1.)像往常一样定义sassOptions

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

2.)为options.data写入“dynamicSASSstring”

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

3.)照常评估SASS

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

注意: 这是假设您的entry.scss导入一些variables.scss定义variables为“默认”。

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

作为一个例子,将它们拼凑在一起

 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); 

那里的“sassGenerator”function可能看起来像

 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 + "';"; } 

这使您可以像以前一样编写您的SASS ,在需要的地方使用SASSvariables 。 它也不会把你束缚到任何“特殊的dynamicsass实现”(即避免在你的.scss文件中使用“underscore / lodash模板”),也意味着你可以利用IDE特性,linting等等。因为你现在刚刚回到正常的SASS写作

此外,它可以很好地转换为非节点/ http /快速编译的用法,例如预先编译通过Gulp给定多个值集的entry.scss多个变体。

我希望这可以帮助你@ChrisWright(和其他)! 我知道我努力寻找有关这个主题的信息,我想这是一个相当常见的用例(想要从数据库,configuration,HTTP参数等传递dynamic值到SASS中)。

在我把头绕在node-sass的importer()方法后,我能够解决这个问题。 我的解决scheme涉及下划线模板和手动读取文件。它不是最优雅或有效的解决scheme,但它只在每个生成的页面上运行一次。 之后,文件被缩小并caching以备未来的请求。

 // 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 }) }); }); } 

使用这个解决scheme,我们可以在我们的SCSS部分中引用一般的下划线variables语法。 举个例子:

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

我正在解决一个类似的问题,但不是在Node中,而是在Java中。 我需要从数据库中呈现SASSvariables来生成网站主题,基于访问网站的客户端。

我探索了一些解决scheme,并通过这个第三方服务https://www.grooveui.com 。 它提供了一个语言不可知的解决scheme来解决这个问题。