【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた
DartSassがなかなか辛かったので
Gulpを修正してみた
目次
DartSassがなかなか辛い
以前、「【Sass】@importを@useに置き換えてみる《FLOCSS対応》」というLibSass
からDartSass
への移行について記事を書きました。
無事@import
記法から@use
・@forward
記法に移行できたのですが、この記事の内容で数ヶ月使ってみたところ、正直前より使いにくくて辛くなってきました。
ざっくり何が使いにくいかというと、
- Glob使えない
- 名前空間めんどい
- コンパイル遅い
などなど。ファイル数が少ない時は耐えれますが、複数のCSSファイル生成したり細かくパーシャルで分けたりって時はけっこう辛いです・・・。
いつまでもGulpでがんばってるから使いにくいのかなーとか考えましたが、「Webpackなら問題なくDartSassれてる」みたいな情報も調べてみて特にない様子。調べ方が悪いのかもしれないし、WebpackがGulpほど苦労がないから誰も記事にしないのかもですけど。
とりあえず現状は引き続きGulpでやっていくつもりなので、自分なりに解決方法探って対応してみました。
Glob使えない問題
gulp-sass-glob
が@use
に対応してないので使えなくなりました。
代わりにgulp-sass-glob-use-forward
というプラグインがあるみたいなのでそれを使います。
jakerambo/gulp-sass-glob-use-forward: gulp task to allow importing directories in your SCSS
https://github.com/jakerambo/gulp-sass-glob-use-forward
インストールします。
$ yarn add -D gulp-sass-glob-use-forward
Gulpファイルに下記のように追記します。
import gulp from 'gulp'
import sass from 'gulp-dart-sass'
import sassGlob from 'gulp-sass-glob-use-forward'
function buildCss() {
return gulp.src('assets/sass/**/*.scss')
.pipe(sassGlob()) //ここで使う
.pipe(sass())
.pipe(gulp.dest('assets/css'))
}
そうすると@use
や@forward
でGlobが使えるようになります。
@use "global/*";
@use "foundation/*";
@use "layout/*";
@use "object/component/*";
@use "object/project/*";
@use "object/utility/*";
こんな感じでフォルダ内のファイルをまとめてglobで読み込めるので、いちいちファイル名指定しなくてもいいし楽。全部まとめた_index.scss
みたいなファイルも用意する必要ないので便利です。
ただし、1点問題がありました。
子階層からglobを使うとうまく機能しない・・・。
// OKな書き方
@use "../global/variable" as g;
@use "../global/mixin" as m;
@use "../global/function" as f;
// NGな書き方
@use "../global/*" as *;
下記の記事で同じ問題点の解決方法について情報があったので試してみましたが解決しませんでした。
gulp-dart-sass で glob したい
https://qiita.com/taqumo/items/8f726268f4723202e451
なので、やはり子階層用に_index.scss
で下記のようなファイルを用意しておいて、
@forward "variable";
@forward "mixin";
@forward "function";
各ファイルの1行目で読み込むようにするしかないみたいです。
@use "../global" as g;
名前空間めんどいだけでメリットない問題
@use
に変えると変数やmixin
などをまとめてパーシャルファイルを読み込んで使う場合、下記のように名前空間が必要になります。
@use "../../global" as g;
.c-hoge{
color: g.$hoge-color;
}
この書き方にしてしばらく使ってみたんですが、名前空間付けるメリットは今の所マジでみつからないです・・・。この例で言うとg.
ってたったの2文字でほんのちょっとの手間ではありますが、たくさん書いてるとこれのせいで作業効率落ちてるんじゃないか?って気持ちになるくらい、変数の前に付けるのが邪魔で仕方ないです。
そんな時はアスタリスク(*
)を使うことで省略できます。
@use "../../global" as *;
.c-hoge{
color: $hoge-color;
}
これで書き味はLibSass
の時とほぼ同じになりました。
共通ファイルを読み込ませる時に相対パス書くのめんどい問題
変数やmixin
をまとめて使いたいので、global/_index.scss
に共通ファイルをまとめています。
global/_index.scss
@forward "variable";
@forward "mixin";
@forward "function";
これを下記のように各ファイルで読み込ませて使っています。
@use "../../global" as *;
この相対パスですが面倒ですね。node_modules
のファイルを使う時も指定が面倒です。
@use "../../../node_modules/swiper/swiper.scss";
これらの相対パス問題についてはgulp-dart-sass
のincludePaths
パラメータで解決します。
mattdsteele/gulp-dart-sass: SASS plugin for gulp
https://github.com/mattdsteele/gulp-dart-sass
gulp-dart-sass
をインストールします。
$ yarn add -D gulp-dart-sass
Gulpファイルは下記のように書きます。
import gulp from 'gulp'
import sass from 'gulp-dart-sass'
import sassGlob from 'gulp-sass-glob-use-forward'
function buildCss() {
return gulp.src('assets/sass/**/*.scss')
.pipe(sassGlob())
.pipe(
sass.sync({
includePaths: ['node_modules', 'assets/sass'], //パスを指定
outputStyle: 'expanded'
}).on('error', sass.logError)
)
.pipe(gulp.dest('assets/css'))
}
こんな感じでnode_modules
へのパスと、sass
のルートディレクトリをincludePaths
で指定しておくと、@use
の後の相対パスを省略できます。
// "../../global" みたいになるのを省略可能に
@use "global" as *;
// "../../../node_modules/swiper/swiper.scss" みたいになるのを省略可能に
@use 'swiper/swiper.scss';
これで各所で共通ファイルを使いたい時にいちいち相対パスを気にしなくてよくなるので少しマシになります。
そもそも共通ファイルを読み込むために1行目に書くこと自体がめんどいですが、それはどうしようもなさそうなので我慢します。
複数ファイルを生成する時にコンパイル遅い問題
gulp-dart-sass
でsass.sync()
という書き方ができるようになっています。
import gulp from 'gulp'
import sass from 'gulp-dart-sass'
import sassGlob from 'gulp-sass-glob-use-forward'
function buildCss() {
return gulp.src('assets/sass/**/*.scss')
.pipe(sassGlob())
.pipe(
sass.sync({ // ← これ
includePaths: ['node_modules', 'assets/sass'],
outputStyle: 'expanded'
}).on('error', sass.logError)
)
.pipe(gulp.dest('assets/css'))
}
これは「同期レンダリング」というものらしいですが、DartSassでは同期レンダリングの方が非同期レンダリングよりも高速になるらしいです。同期レンダリングが何かは正直調べてもよくわからないです。以前の記事「【Sass】@importを@useに置き換えてみる《FLOCSS対応》」でfibers
というパッケージを使うとパフォーマンスが上がるっていう公式の情報があった件と同じようなことで、とりあえず深く考えずに使ってみることにしました。ちなみにfibers
はnode v16以上に対応していないようなので、もう指定する必要はないっぽいです。
とりあえずsass.sync()
で書いてみて、若干コンパイルが早くなった気がします。
あとはLibSass
の時と同じく、gulp-cached
などを使って変更があったファイルとその依存関係のあるファイルのみをコンパイルする様にできれば、マシになりそうです。
修正してみます。
修正に必要なパッケージをインストールします。
$ yarn add -D gulp-cached gulp-dependents
Gulpファイルを修正します。
import gulp from 'gulp'
import sass from 'gulp-dart-sass'
import sassGlob from 'gulp-sass-glob-use-forward'
import cached from 'gulp-cached'
import dependents from 'gulp-dependents'
const dependentsConfig = {
".scss": {
parserSteps: [
/(?:^|;|{|}|\*\/)\s*@(import|use|forward|include)\s+((?:"[^"]+"|'[^']+'|url\((?:"[^"]+"|'[^']+'|[^)]+)\)|meta\.load\-css\((?:"[^"]+"|'[^']+'|[^)]+)\))(?:\s*,\s*(?:"[^"]+"|'[^']+'|url\((?:"[^"]+"|'[^']+'|[^)]+)\)|meta\.load\-css\((?:"[^"]+"|'[^']+'|[^)]+)\)))*)(?=[^;]*;)/gm,
/"([^"]+)"|'([^']+)'|url\((?:"([^"]+)"|'([^']+)'|([^)]+))\)|meta\.load\-css\((?:"([^"]+)"|'([^']+)'|([^)]+))\)/gm
],
prefixes: ["_"],
postfixes: [".scss", ".sass"],
basePaths: []
}
};
function buildCss() {
return gulp.src('assets/sass/**/*.scss')
.pipe(sassGlob())
.pipe(cached('scss'))
.pipe(dependents(dependentsConfig))
.pipe(sassGlob())
.pipe(
sass.sync({
includePaths: ['node_modules', 'assets/sass'],
outputStyle: 'expanded'
}).on('error', sass.logError)
)
.pipe(gulp.dest('assets/css'))
}
gulp-cached
を使うと、キャッシュが作られて、変更のあったファイルのみ処理を通すようになります。
ただし、これだけだと@use
・@forward
・@include meta.load-css
で読み込んだパーシャルファイルを変更して保存したときにはコンパイルされません。依存関係を解決してパーシャルファイルを読み込んでいる元ファイルを辿ってコンパイルするように処理を通す必要があります。
これは@import
の時であればすでに解決されていた問題で、gulp-progenyを使えばOKでした。しかし@use
ではgulp-progeny
は対応していません。別の解決方法として下記記事を見つけたのでそのまま使わせてもらいました。
@useまたは@include meta.load-cssで読み込んでるscss(sass)ファイルを更新してもコンパイルされない問題解決
https://qiita.com/yamabero/items/ea4f4c3c1a23a6ed778c
gulp-dependents
というパッケージを使います。
ただし、なぜかこれを使うと途中でgulp-sass-glob-use-forward
が無効化されGlobがエラーになってしまいます。そのためgulp-dependents
の前後にgulp-sass-glob-use-forward
の処理を繋いでいます。
.pipe(sassGlob()) //Globを有効化
.pipe(cached('scss')) //キャッシュ
.pipe(dependents(dependentsConfig)) //@use・@forwardの依存関係を解決(依存元のファイルを処理に通す)
.pipe(sassGlob()) //依存元のファイルのGlobを有効化
あまり良くはない書き方にはなるんでしょうが、こうしないとうまくコンパイルされなかったので仕方なく。
こういうのをちゃんと解決しようと思ったら自分でプラグイン作ったりしないといけないんでしょうね。。。
そんな時間ないんでとりあえずの対応です。
これで変更があったファイルと依存関係のあるファイルだけコンパイルできるようになりました。
1つだけ注意点。
この手法の場合、依存関係を辿った先の親ファイルに必ず共通ファイルも読み込ませることが必要です。
@use "global/*"; // ← 必要ないけど読み込ませる
@use "foundation/*";
@use "layout/*";
@use "object/component/*";
@use "object/project/*";
@use "object/utility/*";
こうしておかないと、例えばglobal/_variable.scss
という変数をまとめたファイルで変更して保存した時に、依存関係を辿った先に@use
が書かれてるところがない場合、コンパイルされません。
下記でも生成するCSSの結果は同じですが、
@use "foundation/*";
@use "layout/*";
@use "object/component/*";
@use "object/project/*";
@use "object/utility/*";
globalディレクトリ内のファイルの更新は無視されるのでglobal/_variable.scss
を更新してもコンパイルが走りません。そのため必要なくてもファイルの変更時に更新させたい場合は@use
で読み込ませておくことが必要になります。
最後少しややこしくなりましたが、とりあえずこれで複数ファイルを生成する時でも変更があったファイルのみコンパイルが走るので処理が早くなりました。
@importの時にできていたネストさせてパーシャルをインポートする方法が@useでできない問題
例えば下記のような使いまわしたいCSSがあるとして、
_scope.scss
h1 {
font-size: 30px;
font-weight: bold;
// ...
}
h2{
// ...
}
h3 {
// ...
}
p{
// ...
}
@import
の時は下記のように書いていました。
.p-hogehoge{
@import 'scope'
}
この書き方でコンパイルされたCSSは下記です。
.p-hogehoge h1 {
font-size: 30px;
font-weight: bold;
// ...
}
.p-hogehoge h2{
// ...
}
.p-hogehoge h3 {
// ...
}
.p-hogehoge p{
// ...
}
これは下記のように@use
に変えてもうまくいきません。
.p-hogehoge{
@use 'scope' // エラーになる
}
こういう場合は@include meta.load-css
を使います。
@use "sass:meta";
.p-hogehoge{
@include meta.load-css('scope');
}
これで@import
の時と同じ結果が得られます。
ちなみに一つ上の項目で@include meta.load-css
で読み込んだパーシャルファイルもgulp-dependents
で依存関係を解決されるようになっているので、読み込んだパーシャルファイルを更新した時もコンパイルが走るので問題なく使えます。
さいごに
DartSassで開発するにあたって、不都合に感じた部分を自分なりに修正してみました。
少しマシになった気がします。でもまだまだ以前ほど快適とは言えません。
DartSassは複数人がCSSを触るような規模のチーム開発ではもしかしたら何らかのメリットがあるのかもしれませんが、弊社のようなコーディング〜WordPress化・システム開発までほとんどフロントエンド1人で担当するような環境ではメリットが見つからないです。CSS設計にFLOCSSを使っていることもありますが、@import
の時の方がルールもシンプルで他人に説明しやすく、作業に集中できたと感じます。
よくこういう新しい手法が出たときは慣れの問題とか言いますが、今回は慣れとかの問題じゃなく本当に手間が増えた感覚しかないです。
まだ過渡期ではあると思うので、有用なプラグインなど確立した手法がいくつか出てきたら開発効率が良くなっていくと思いますが、今のところ細かい不都合に対して調べて対応してもどこかに懸念点が残りモヤモヤするばかりです。
うー〜ん・・・もう少しいろいろと探ってみて自分なりの正解を見つけます。