私が作業しているアプリケーションでは、クライアントでレンダリングする前にSASSを動的にコンパイルする必要があります(キャッシュシステムが来るので、心配しないでください)。現在、私は node-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;
}
_
しわは、Nodeからの動的データを渡して、通常のSASS変数のようにコンパイルする必要があるということです。最初に 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はアンダースコアの変数構文を好まなかった。
Nodeアプリケーションから動的変数をSASSに渡すにはどうすればよいですか?
私は非常によく似た状況にいることに気づきました。 (変数として)全体で使用される動的な値/変数を受け入れる必要のある既存のSASSがたくさんありました。私はもともと一時ディレクトリ/ファイルを作成し、proxy_entry.scss
とvariables.scss
とbootstrap実際のentry.scss
目的のSASS変数が宣言されているこれは正常に機能し、目的の結果を達成しましたが、少し複雑に感じました...
非常に簡単な解決策があることが判明しましたnode-sassのoptions.data
オプションのおかげで利用可能です。これは、「評価されるSASS文字列」を受け入れます。
型:文字列デフォルト:null特殊:ファイルまたはデータを指定する必要があります
レンダリングするためにlibsassに渡す文字列。 @importディレクティブを使用するときにlibsassがファイルを検索できるように、これと組み合わせてincludePathsを使用することをお勧めします。
これにより、すべての一時ディレクトリとファイルを作成/管理する必要が完全になくなりました。
解決策はこのようなものになります
var sassOptionsDefaults = {
includePaths: [
'some/include/path'
],
outputStyle: 'compressed'
};
options.data
の「動的SASS文字列」を書くvar dataString =
sassGenerator.sassVariables(variables) +
sassGenerator.sassImport(scssEntry);
var sassOptions = _.assign({}, sassOptionsDefaults, {
data: dataString
});
var sass = require('node-sass');
sass.render(sassOptions, function (err, result) {
return (err)
? handleError(err);
: handleSuccess(result.css.toString());
});
注意:これは、entry.scss
が変数を「デフォルト」として定義するvariables.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({}, 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 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
ファイル全体で "アンダースコア/ lodashテンプレートを使用することを回避します)。また、IDE機能、リントなど...あなたは今ちょうど通常のSASSの記述に戻るなので、まったく同じです。
さらに、Gulpなどを介して複数の値セットを指定してentry.scss
の複数のバリエーションをプリコンパイルするなど、node/http/on-comp-on-the-fly以外の使用法にもうまく変換されます。
これが@ChrisWright(およびその他)の役に立てば幸いです!私は主題に関する情報を見つけるのに苦労したことを知っており、これはかなり一般的なユースケースだと思います(動的な値をデータベース、構成、HTTPパラメータなどからSASSに渡すことを望んでいます...)。
Node-sass ' importer()
メソッドに頭を包んだ後、これを解決できました。私のソリューションは、アンダースコアテンプレートを使用し、入ってくるファイルを手動で読み取ることでした。これは最もエレガントで効率的なソリューションではありませんが、生成されたページごとに1回だけ実行されます。その後、ファイルは縮小され、将来のリクエストのためにキャッシュされます。
// 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 })
});
});
}
このソリューションを使用すると、SCSSパーシャル内の通常のアンダースコア変数構文を参照できます。例として:
body {
color: <%= data.colour %>;
}
NodeではなくJavaで。同様の問題を解決しました。Webサイトにアクセスしているクライアントに基づいて、Webサイトのテーマを生成するデータベースからSASS変数をレンダリングする必要がありました。
私はいくつかの解決策を探り、このサードパーティのサービスに出会いました https://www.grooveui.com 。この問題を解決するための言語に依存しないソリューションを提供します。