【WordPress】GA4連携の人気記事ランキング機能を自作プラグイン化してみた
【Sass】@importを
@useに置き換えてみる
《FLOCSS対応》
目次
Sassの@import記法が廃止予定
Sassの@import
記法が2021年10月1日までに非推奨になり、翌年2022年10月1日までに廃止される予定です。その後は@use
や@forward
という新しいルールの記法で対応することになるのですが、そのまま置き換えても動かないので、各所調整や変更が必要になります。
筆者はここ5年くらいの制作全般でCSS設計に「FLOCSS」を使っています。FLOCSSは@import
に依存しまくった設計でして、Gulpなどのビルド環境含め修正するのがかなり面倒くさくて、去年この変更の話を知ってから「やらなきゃな〜」と思いつつ見て見ぬふりをしていたら1年以上経ってしまいました。笑
そろそろ覚悟を決めて修正しようと思います。
SassをLibSassからDart Sassに変える
これまでnpmでnode-sass
というパッケージが主流でしたが、これが「LibSass」と言われるものを使っていて、2020年10月に非推奨となりました。代わりに今後は「Dart Sass」を使っていくことになるのですが、今までnode-sass
を使っていた場合は、新しくsass
というDart Sass用のパッケージに変更する必要があります。
# node-sassをアンインストール
$ yarn remove node-sass
# sass(Dart Sass)とfibersをインストール
$ yarn add -D sass fibers
fibers
はDart Sassの処理速度を上げるために必要なパッケージとのこと。詳しくはDart SassのGithubに書いてありますが、正直細かいことはよくわかりませんでした。内部的に使っている関数のパフォーマンスを補うために使うみたいなことが書いてます。別になくても動くようにしてるけど、あった方が早く処理できるから使ってねってことだと思います。公式がそう言ってるので使っておきましょう。
Gulpファイルを書き換える
未だにSassのコンパイルにGulp使ってるおじさんなので、Gulpファイルを修正します。
Webpack派の人は他の記事をお探しください。GulpでもWebpack使えるけど今回は割愛します。
Gulp4 + Babelで書きます。
import gulp from 'gulp';
import sass from 'gulp-sass';
import dartsass from 'sass';
sass.compiler = dartsass;
import fiber from 'fibers';
import browserSync from 'browser-sync';
function buildCss() {
return gulp
.src('./sass/**/*.scss', {
allowEmpty: true,
sourcemaps: true,
})
.pipe(
sass({
fiber: fiber,
outputStyle: 'expanded',
})
)
.pipe(
gulp.dest('./css', {
sourcemaps: '.',
})
)
.pipe(
browserSync.reload({
stream: true,
})
);
}
function browsersync(done) {
browserSync.init({
proxy: 'localhost/test',
open: 'external',
});
done();
}
function watcher(done) {
gulp.watch('./**/*.scss', buildCss);
done();
}
exports.default = gulp.series(watcher, browsersync);
従来の記述との変更ポイントは2つあります
まず1つ目。
import sass from 'gulp-sass'
import dartsass from 'sass'
sass.compiler = dartsass;
gulp-sassのコンパイラにDart Sassを使うように設定します。sass.compiler
に新しくインストールしたDart Sassのパッケージを代入します。これでGulpでもDart Sassでコンパイルできるようになります。
そして2つ目。
import fiber from 'fibers'
.pipe(
sass({
fiber: fiber,
outputStyle: 'expanded',
})
)
fibers
をインポートしてコンパイルのオプションに指定します。前述しましたが処理高速化のためになります。
これでDart Sassが使えるようになりました。
@importを@use・@forwardに置き換える方法
続いてscssファイル側で廃止予定の@import
記法を新しい記法に書き換えます。
ただ、残念ながら@import
をそのまま別の何かに書き換えても動くようになりません。@use
と@forward
というまた違うルールで置き換えていきます。
これまでは下記に例示する通り、_variable.scss
のようなパーシャルを別ファイルから読み込んでいれば、それ以降で変数や関数、mixinをファイルをまたいでどこからでも呼び出して使えていました。
_variable.scss
$width : 900px;
style.scss
@import 'variable';
@import 'component/bar'; //変数を読み込んだ後に別ファイルをインポートすると
.foo {
width : $width;
}
component/_bar.scss
.c-bar {
width : $width; //ファイルをまたいでも先に読み込んだファイルの変数が使える
}
つまり読み込む順番さえ調整すれば、@import
を入れ子にしまくっても先に読み込んだファイルの変数がそのまま使えます。これが@import
の特性でしたが、@use
・@forward
ではそのような特性はなくなります。
@use
@use
を使う場合、名前空間を使って変数や関数をどのファイルのものか明示する必要があります。
@import 'variable';
.foo {
width : $width;
}
従来は@import
を使って↑のように書いていましたが、これが@use
になると、
@use 'variable' as v;
.foo {
width : v.$width;
}
↑こういう書き方に変わります。@use
で呼び出したファイルにas
を使って名前空間を付け、変数名にその名前空間v
を付けて使います。
@use 'variable';
.foo {
width : $width;
}
↑のように変数名をそのまま書くと、$width
がUndefined variableとなりエラーになります。
これがどういうことかと言うと、変数がグローバルではなくファイルスコープになったということです。今まで@import
で読み込んでいた場合は、先に読み込んでさえいれば後から読み込んだファイルの変数にはどこからでもアクセスできました。しかし@use
では、ファイルの先頭で明示的に変数の入ったファイルを読み込み、その変数には名前空間を使ってしかアクセスできなくなります。「ここで使っている変数はこのファイルの変数だよ」って感じで、変数がどこから来たのか明確にしていくって感じですね。ちなみに変数だけでなく、mixinや関数も同じです。
@use 'variable' as v;
@use 'mixin' as m;
.foo {
width : v.$width-sp;
@include m.min-screen(v.$size-pc) {
width : v.$width-pc;
}
}
ファイルを読み込む時にas
で名前空間を付けて、変数や関数を使う時には名前空間.変数名や関数名
のように使います。
まぁ確かにこのルールになると、複数で開発する時とか他の人が書いたコードを修正するときなんかはわかりやすいのかも。突然出て来た独自のmixinや変数って、自分ルールでCSSを設計してた場合に、どこに書いてるか、上書きされてないか、とかをいちいちファイルを探して調べる必要があるケースが想像できます。名前空間があれば変数やmixinを上書きするリスクはなくなるし、ファイル分けて使いたいなら各ファイルの先頭に@use
で元の場所を明示的にしておけばわかりやすくていいよねってことなのかなーと思います。
@forward
@forward
はファイルをまたいで値を受け渡すことができます。
これまでFLOCSSなどのCSS設計で運用してきた場合、@import
を入れ子にしたい場合があります。
それを下記のように@use
を使おうとすると動きません。
_variable.scss
$red : #f00;
$yellow : #ff0;
foundation/_index.scss
@use 'variable'
@use 'mixin'
@use 'function'
style.scss
@use "foundation" as v;
.foo {
//変数が読み込めずエラーになる
background-color : v.$red;
}
意図としては関数や変数のパーシャルを1ファイルにまとめてインポートして使いたいのですが、@use
ではそれができません。こういった場合に@forward
を使います。
foundation/_index.scss
@forward 'variable'
@forward 'mixin'
@forward 'function'
style.css
@use "foundation" as global;
.foo {
background-color : global.$red;
//mixinやfunctionも@forwardを使っているとglobalという名前空間でまとめて呼び出せる
@include global.min-screen(801px) {
background-color : global.$yellow;
}
}
ただし、@use
と違ってファイル間でスコープを受け渡しするだけの役割なので、@forward
を使ったファイル内で変数として使うことはできません。
foundation/_index.scss
@forward 'variable' as v
@forward 'mixin'
@forward 'function'
.bar {
// これはエラーになる
color : v.$red;
}
この場合は@use
と併記する必要があるみたいです。
@forward 'variable'
@forward 'mixin'
@forward 'function'
@use 'variable' as v;
.bar {
color : v.$red;
}
@use
と@forward
は役割が全く違うので同時に使っても問題ないようです。
ちなみに@forward
で名前空間を定義した場合は、受け渡した先で使えるプレフィックス(接頭辞)となります。
foundation/_index.scss
@forward 'variable' as v-*;
@forward 'mixin' as v-*;
style.scss
@use 'foundation' as global;
.foo {
background-color : global.$v-red;
@include global.m-min-screen(801px) {
background-color : global.$v-yellow;
}
}
これ公式に書いてなくて若干ハマりました。@forward
で付けたプレフィックスはmixinや関数のときはそのまま先頭に着くのですが、変数の場合は$
の後ろに付きます。
background-color : global.$v-red; //○
background-color : global.v-$red; //× エラーになる
公式見てもmixinの例しかないので、そのまま先頭に付けてあれ?ってなりました。@forward
のプレフィックスはあまり使う機会なさそうなのでいいんですけどね。
FLOCSSを@useに合わせて調整する
@import
を使いまくって、どこからでも変数使い放題のCSS設計のFLOCSSですが、すべてのパーシャルファイルに@use
で変数やmixinを読み込む必要があります。
そのため、変数などのファイルは新たにglobal
というフォルダを作り、そこから一括で読み込めるようにします。
FLOCSSのディレクトリ構成
├── /sass/
├── /global/ ← このフォルダを作る
├── /foundation/
├── /layout/
├── /object/
├── /component/
├── /project/
├── /scope/
└── /utility/
└── style.scss
これまでfoundationフォルダに入れてあった_variable.scss
、_function.scss
、_mixin.scss
などの共通ファイルをglobalフォルダに移動させ、global/_index.scss
から一括で読み込めるように下記のファイルを作ります。
global/_index.scss
@forward "variable";
@forward "mixin";
@forward "function";
あとは各ファイルの先頭に下記のように読み込みます。(相対パスの位置は適宜変えてください。)
@use '../global' as g;
そしてcomponentやprojectの各ファイル内で変数やmixinに名前空間を振っていけばOKです。
component/_foo.scss
@use '../global' as g;
.c-foo {
background-color : g.$red;
@include g.min-screen(801px) {
background-color : g.$yellow;
}
}
ひとまずこれで@import
は置き換えられました。
あとはstyle.scss
の@import
を@use
に変更すれば、FLOCSSの変更対応はひとまず完了です。
@use "foundation";
@use "layout";
@use "object/component";
@use "object/project";
@use "object/utility";
↑各フォルダに_index.scss
というパーシャルを作って読み込むことを想定しています。
ビルトインモジュールについて
@import
の話とは別になりますが、Dart Sassでのその他の変更についても触れておきます。
lighten
やdarken
といったSass関数や、60px / 3
のような除算処理などが、LibSassの時はコンパイル時に自動で組み込まれていたのですんなり使えていましたが、Dart Sassからは「ビルトインモジュール」となり扱い方が変わる様です。
Sass: Built-In Modules
https://sass-lang.com/documentation/modules
明示的に使いたいモジュールを読み込んで、新しい記法に変えないといけなくなります。そのままlighten
などと書いても使えなくなる模様です。
この記事の執筆時点(2021.6.2)では、前述したGulpのコードを使った場合はまだlighten
やdarken
、rgba
は問題なくコンパイルされていました。おそらく段階的に使えなくなっていくのでしょう。
Sass関数の書き換え
今後、Sass関数は下記のようにモジュールを読み込んで別の書き方に変更されます。
@use "sass:color";
.foo {
//lighten
color.scale(#fad, $lightness: 30%);
}
.bar {
//darken
color: color.scale(#fad, $lightness: -30%);
}
.baz {
//rgba
color: color.scale(#fad, $alpha: -40%);
}
↓コンパイル結果
.foo {
//lighten
color: #ffc4e7;
}
.bar {
//darken
color: #ff2baa;
}
.baz {
//rgba
color: rgba(255, 170, 221, 0.6);
}
sass:color
については他にも関数があるので、詳しくは公式ドキュメントで確認してみてください。
sass:color
https://sass-lang.com/documentation/modules/color
除算処理の書き換え
60px / 3
のような除算(割り算)処理はすでにDart Sassでは使えなくなっています。
.foo {
padding : (60px / 3); //× エラーになる
}
下記のように書き換えます。↓
@use "sass:math";
.foo {
padding: math.div(60px, 3);
}
関数やmixinをたくさん使っている人は、この修正がかなり大変だろうなと思います。
最近はcssでcalc()
が使えるのでそっちに書き換えた方が楽かもしれませんね。
さいごに
FLOCSSで使われている@import
を@use
に置き換える方法について、下記内容をメモしました。
- LibSassからDart Sassへの変更方法
- Gulpファイルの変更方法
- scssファイルの@importを@use・@forwardに置き換える方法
- @useに合わせたCSS設計「FLOCSS」の調整方法
- ビルトインモジュールでSass関数などを書き換える方法
@import
は使えなくなるのがわかっているので、変更方法は早めに押さえておきましょう!
個人的な感想としては、正直@use
への変更は「めっちゃめんどい」です!笑
最終的に文句が出ちゃいましたけど、今回のようなSassの致命的な変更に限らず、TypeScriptにしろVueにしろ、GulpにしろWebpackにしろ、Nodeにしろnpmにしろ、古くなったルールを新しいルールに置き換えるっていう作業はよくあることなので、こういった機会に改めて内容を整理してみると新しい発見があったりして勉強になります。
久々にGulpファイル書いたら、開発に使ってるGulpファイルも整理したくなって来たのでまたそれについても更新しようかな。いい感じにできたら過去記事リライトします!
参考サイト
Dart Sass(@use)の基本的な書き方と@importから乗り換える方法
Sassで除算するときはsass:mathモジュールのdiv関数を使おう
追記(2021.11.24)
その後、この記事の設定で使いにくかった部分について修正してみました。