这是我到目前为止工作的。为简洁起见,删除了其他特定于项目的代码:
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; }
皱纹就是现在我需要从Node传递动态数据,并且像普通的SASS变量一样编译。最初我尝试使用PostCSS,因为我注意到变量注入是something it could do.不幸的是,这没有工作。 PostCSS在编译阶段开始,在这一点上惨败。
接下来,我尝试使用underscore模板尝试使用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不喜欢下划线的变量语法
TL; DR
如何从我的Node应用程序中传递动态变量到SASS?
附加信息
>我的团队和我并没有完全不利地转向像Stylus这样的东西;然而,我们迄今已取得重大进展,这将是一个痛苦。
解决方法
事实证明,有一个更简单的解决方案,由于node-sass’s options.data
选项。这接受“要评估的SASS字符串”。
Type: String Default: null Special: file or data must be specified
A string to pass to libsass to render. It is recommended that you use includePaths in conjunction with this so that libsass can find files when using the @import directive.
这完全消除了编写/管理所有临时目录和文件的需要。
Visual TL; DR
解决方案归结为这样的事情
1.)像往常一样定义sassOptions
var sassOptionsDefaults = { includePaths: [ 'some/include/path' ],outputStyle: 'compressed' };
2.)为options.data写入“动态SASS字符串”
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导入一些将变量定义为“默认值”的变量.scss。
// 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({},{ data: dataString }); // 3.) render sass as usual sass.render(sassOptions,result) { return (err) ? handleError(err); : handleSuccess(result.css.toString()); }); } // Example usage. dynamicSass('some/path/entry.scss',{ 'someColor': 'red','someFontSize': '18px' },someSuccessFn,someErrorFn);
“sassGenerator”功能可能看起来像什么
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变量来使用SASS变量。它也不会使你陷入任何“特殊的动态sass实现”(即避免在你的.scss文件中使用“undercore / lodash模板”),这也意味着你可以利用IDE功能,linting等…你现在只是回到写正规的SASS,就一样了。
此外,它很好地转换为非节点/ http /编译的实时用法,例如通过Gulp等预先编译entry.scss的多个变体,给出多个值集合
我希望这可以帮助你@ChrisWright(和其他人)出来!我知道我很难找到关于这个主题的信息,我想象这是一个相当常见的用例(想从数据库,配置,HTTP参数等传递动态值到SASS)。