Ususama で LibSass から Dart Sass への乗り換えを試験したのでメモしておきます。
経緯
こちらの記事を拝見して自分も乗り換えないと、と思った次第。
特に Ususama では Scss のコンパイラとして gulp-sass
を利用していますが、現時点(2020/11/9)では gulp-sass
はデフォルトだと node-sass
を使用しています。
Node-sass is a library that provides binding for Node.js to LibSass, the C version of the popular stylesheet preprocessor, Sass.
node-sass
は内部的には LibSass を使用しているため、 Dart Sass を使用するならば切り替えが必要になります。
その他にも色々手を加えたいところはあるのですが、一気に変更するとデバッグが大変なことになるのでできることから少しずつ……という気持ちで、 Dart Sass への切り替えをやってみたいと思います。
背景
全てはこの記事ですね。2020/10/26にタイトルの通り、 LibSass が非推奨として宣言されました。
LibSass, Dart Sass
そもそも LibSass や Dart Sass とは、というところも軽く触れておきます。
(比較項目) | LibSass | Dart Sass |
---|---|---|
言語 | C++製 | Dart製 |
1.0.0リリース日 | 2012/10/16 | 2018/3/27 |
備考 | 普及率高 | 公式推奨 |
「Dart Sass の方が後発」「公式は Dart Sass 推奨」というところを押さえておけば良いかと思います。
この他、 Dart Sass の機能についてはSass: Feature Watch: CSS Imports and CSS Compatibilityに詳しく書かれています。
- プレーンな css のインポートをサポート
- css の
min()
,max()
をサポート - メディアクエリでの範囲指定
Dart Sass には以上のような機能が盛り込まれています。
しかし、一番大きいのは以下の点ではないでしょうか。
@import
から@use
,@forward
へ
分割したscssファイル、パーシャルを読み込む際に使用していた @import
が将来的には廃止予定(2022/10予定)で、代わりに @use
を使うように、とのことです。
この他、 lighten()
, saturate()
, adjust-hue()
, map-get()
辺りも変わります。
Dart Sass へ
冒頭に記載した通り、 gulp-sass
はデフォルトでは node-sass
(LibSass) を使用しているため Dart Sass への切り替えが必要です。
Dart Sass に切り替えるということは、上述の通り @import
から @use
, @forward
への書き換えておくべきでしょう。
ということで、冒頭の乗り換え試験に至るわけです。
Dart Sass への切り替え
まずは gulp-sass
のコンパイラを切り替えるところから。
You can choose whether to use Dart Sass or Node Sass by setting the sass.compiler property. Node Sass will be used by default, but it’s strongly recommended that you set it explicitly for forwards-compatibility in case the default ever changes.
gulp-sass
はコンパイラの切り替えが可能とのことなので公式に則って Gulpタスク を書き換えます。
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const sass = require('gulp-sass');
sass.compiler = require('sass'); // 追記
const autoprefixer = require('gulp-autoprefixer');
const Fiber = require('fibers'); // 追記
const scss = () => {
return gulp.src(
`./src/scss/**/*.scss`,
{
ignore: [
`./src/scss/assets/bootstrap/bootstrap.scss`,
`./src/scss/assets/bootstrap/honoka/bootstrap/**`,
`./src/scss/assets/bootstrap/honoka/honoka/**`
]
})
.pipe(plumber({
errorHandler: notify.onError({
message: 'Error: <%= error.message %>',
title: 'sass'
})
}))
.pipe(sass({
fiber: Fiber, // 追記
outputStyle: 'compressed'
}).on('error', sass.logError))
.pipe(autoprefixer({
cascade: false
}))
pipe(gulp.dest('./dist/'));
};
Scss をコンパイルするタスクの中で、 sass.compiler = require('sass');
を追記することでコンパイラを切り替えています。
注意する点としては、 Dart Sass のコンパイラのパッケージ名が sass であるということ。若干紛らわしいです。あと、高速化のために fibers
も追加しています。
"devDependencies": {
// 略
"gulp-sass": "^4.1.0",
"sass": "^1.28.0", // 追加
"fibers": "^5.0.0", // 追加
"gulp-autoprefixer": "^7.0.1",
// 略
},
以上を踏まえて package.json
にも sass
と fibers
を追加します。
コンパイラの切替はこれでOKです。
コードの書き換え
続いてはコードの書き換え。
@import から @use, @forward へ
基本的には @import
を @use
に書き換えていくのですが、変数や mixin をさらに他のscssファイルで使用したい場合は @forward
にします。
例えば以下のように src/scss/layout/_l-main.scss
→ src/scss/global/_index.scss
→ src/scss/global/_scss_variables.scss
という場合。
src/scss/global/_scss_variables.scss
@charset "utf-8";
@use "sass:color";
@use "var" as g;
$us-main-color_d: color.scale(g.$us-main-color, $lightness: -8%);
$us-main-color_l: color.scale(g.$us-main-color, $lightness: 8%);
$us-accent-color: color.adjust(g.$us-main-color, $hue: 150deg);
$us-link-color: color.adjust(g.$us-main-color, $hue: 210deg);
$us-link-v-color: color.scale($us-link-color, $lightness: -15%);
$us-link-ha-color: color.scale($us-link-color, $lightness: -8%);
$us-background-position: center center;
$us-eyecatch-height: 60vh;
$us-line-height: 1.6;
$us-letter-spacing: 0.15rem;
変数の宣言のパーシャル。
src/scss/global/_index.scss
@charset "utf-8";
@forward "var"; //変数(ejs等と共通)
@forward "scss_variables"; //変数
@forward "mixin"; //mixin
@forward "../assets/bootstrap/bootstrap"; //bootstrap
@forward "../../../node_modules/brand-colors/dist/latest/scss/brand-colors.latest"; //ソーシャルメディアなどのブランドカラー
@use "../../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome"; //以下4つFontAwesome
@use "../../../node_modules/@fortawesome/fontawesome-free/scss/solid";
@use "../../../node_modules/@fortawesome/fontawesome-free/scss/regular";
@use "../../../node_modules/@fortawesome/fontawesome-free/scss/brands";
global/_scss_variables.scss
等を読み込んでいるパーシャル。
src/scss/layout/_l-main.scss
@charset "utf-8";
@use "../global" as g;
.l-main {
background-color: g.$us-bg-color;
color: g.$us-color;
}
最後に、 global/_index.scss
を読み込んで実際に global/_scss_variables.scss
の変数を使用しているパーシャル。
この例のように、実際に global/_scss_variables.scss
の変数を使用するscssファイルにインポートされる中間のscssファイル(ここでは global/_index.scss
)では @use
ではなく @forward
を使います。
global/_index.scss
で global/_scss_variables.scss
を @use
で読み込んでしまうとファイルスコープがそこで閉じてしまうので、 layout/_l-main.scss
からは見えなくなってしまいます。
その他の留意点としては以下。
@use ... as hoge;
で名前空間の指定が可能layout/_l-main.scss
では@use "../global" as g;
でg
という別名を付けているのでg.$us-bg-color
というように変数名も名前空間付きで指定
_index.scss
はディレクトリ名のみで読み込むことが可能layout/_l-main.scss
では@use "../global" as g;
でglobal/_index_.scss
を読み込んでいます
この辺りの感覚は個人的には ECMAScript の import
, export
に近いのではないかと思います(export
は吐き出し元の方に記述しますが)。(循環参照になっていなければ)複数個所で同じものを読み込んでも良いとか。
ファイルスコープや名前空間の考え方はよりメンテナンス性を向上させることになると思う(@import
だとどこで変数等が宣言されているのか追いづらかった)ので良いと思います。
その他の個人的に引っかかった留意点は以下。
- ファイルの読み込みルールが変わったので、今まで FLOCSS の
foundation
ディレクトリにあった変数や mixin の塊は新たにglobal
ディレクトリを作成してそちらに移動 global/_index_.scss
が Bootstrap の読み込みと自身の変数の読み込みを行っていて、最終的には同じ名前空間で展開されるので$link-color
が名前的にバッティングしました- 回避するため、自身の変数群にはプレフィックスとして
us-
を最初に付けるようにしました
- 回避するため、自身の変数群にはプレフィックスとして
- 今まで
fs
でファイルの内容を読み込み→scss拡張子で書き出ししている部分があったのですがその部分を削除- css を直で読み込みできるようになったため
.stylelintrc.json
で"ignoreAtRules"
に追加
.stylelintrc.json
// 略
"rules": {
"at-rule-no-unknown": [
true, {
"ignoreAtRules": [
"function","if","else if","else","for","each","include","mixin","content","use","forward" // "use","forward" を追加
]
}
],
// 略
},
// 略
ビルトインモジュール
続いては lighten()
, saturate()
, adjust-hue()
, map-get()
辺りのSass関数をビルトインモジュールに書き換えます。
上述 global/_scss_variables.scss
で既に書き換えを実施していますが、再掲。
src/scss/global/_scss_variables.scss
@charset "utf-8";
@use "sass:color";
@use "var" as g;
$us-main-color_d: color.scale(g.$us-main-color, $lightness: -8%);
$us-main-color_l: color.scale(g.$us-main-color, $lightness: 8%);
$us-accent-color: color.adjust(g.$us-main-color, $hue: 150deg);
$us-link-color: color.adjust(g.$us-main-color, $hue: 210deg);
$us-link-v-color: color.scale($us-link-color, $lightness: -15%);
$us-link-ha-color: color.scale($us-link-color, $lightness: -8%);
$us-background-position: center center;
$us-eyecatch-height: 60vh;
$us-line-height: 1.6;
$us-letter-spacing: 0.15rem;
lighten()
,darken()
:color.scale()
に置換。第一引数が色、第二引数のキーは明度($lightness
)・彩度($saturation
)の指定、値は指定の値(マイナス値だとdarken()
,desaturate()
)color.lightness()
,color.saturation()
でも良さそう
adjust-hue()
:color.adjust()
に置換。第二引数のキーを色相($hue
)指定
以上のようになっています。なお、ビルトインモジュールの使用にはモジュールの読み込みが必要で、上述の色系の場合は @use "sass:color";
を冒頭で指定する必要があります。
src/scss/_plugins/articlesns/_articlesns.scss
@charset "utf-8";
$sns-array: (
Twitter: (
color: $bc-twitter,
darkness: 8%
),
Facebook: (
color: $bc-facebook,
darkness: 12%
),
Hatena: (
color: $bc-hatena-bookmark,
darkness: 8%
),
Line: (
color: $bc-line,
darkness: 5%
),
Pocket: (
color: $bc-pocket,
darkness: 12%
),
Feedly: (
color: $bc-feedly,
darkness: 8%
)
);
//SNSシェアボタンを付与
.c-btn_news {
&,
&:link,
&:visited {
color: darken($bg-color, 4%);
.fa.fa-fw {
margin-right: 0.1rem;
}
}
&:hover,
&:active,
&:focus {
text-decoration: none;
color: $bg-color;
}
@each $key, $val in $sns-array {
&#{$key} {
background-color: map-get($val, color);
&:hover,
&:active,
&:focus {
background-color: darken(map-get($val, color), map-get($val, darkness));
}
}
}
}
map-get()
は map.get()
に変更。こちらも使用のためには @use "sass:map";
を冒頭で宣言する必要があります。
これで一通り書き直していって、元通り動くことを確認。
参考
契機
gulp-sass
fibers
@import から @use, @forwward へ
- Sassのモジュールシステムを@importから@useに移行する方法を考えてみた | Rriver
- Sassの@use, @forwardについて | Rhyztech blog
- コピペで簡単!GulpでDart Sass入門 | 株式会社 エヴォワークス -EVOWORX-
- Sassの新しいモジュールシステム – シフトブレイン/スタンダードデザインユニット