公開日: 2025年3月10日

【Sass】 FLOCSS 指向で @import から @use / @forward へ移行する

つい最近まで知らなかったのですが、Sass の @import ルールが廃止される (廃止された?) とのことです。当サイトでは FLOCSS 指向で作成したスタイルシートを使っておりまして、@import からも多大なる恩恵を受けているため、こりゃいかんということで対応を行ってみました。

本稿に登場する用語等について

本稿に登場する用語については説明しない (できない) ので、詳細は下記のリンク先等を参照してください。

FLOCSS について:

Sass の「@なんちゃら」 ルール (At-Rules) について:

@use / @forward への移行に関しては、次のサイトが FLOCSS 的な観点から解説されていて、大変参考になりました:

Dart Sass について

Sass の公式サイト (https://sass-lang.com) によると、Sass の実装は Dart Sass、LibSass (≒ Node Sass) 、Ruby Sass の 3 種類があり、このうち現在でも継続的にサポートされているのは Dart Sass のみです。ですので、今回の移行作業に関わらず Sass を利用するなら Dart Sass を使うようにしましょう。npm のパッケージ名でいうと、その名も「sass」が Dart Sass になります。

Dart Sass では件の @import は既に非推奨になっており、バージョン 3.0.0 で削除される予定とのことです:

As of Dart Sass 1.80.0, the @import rule is deprecated and will be removed from the language in Dart Sass 3.0.0. Prefer the @use rule instead.

出典: Sass 公式サイト - @import

ちなみに 2025 年 3 月現在の最新バージョンは 1.85.1 となっています。

@use と @forward

@import のなにが問題なのか?は前出の Sass 公式サイトに 5 項目 (も) 挙げられています。そうとも知らず私は「@import って便利だなあ」と感謝しながら普通に使ってました。のんきなものですね。

で、これを @use と @forward に置き換えよというわけです。@use も @forward も他の Sass ファイル (モジュール) をロードするための宣言ですが、前者は @use を行ったファイル自身がそのモジュールを使用するのに対し、後者はロードしたモジュールを自身では使用せず、自身を @use した別の Sass ファイルがそのモジュールを使えるように取り次ぎます。

例えば _variables.scss で定義されている$site-colorを _main.scss で参照したかったら、次のように @use を使って _variables.scss をロードします。

_main.scss
@use "variables";
.p-main {
    background: variables.$site-color;
}

ここを @use ではなく @forward にしてしまうと、エラーになります。

sass.Exception [Error]: There is no module with the namespace "variables".

@use でロードしたモジュールは、@use したファイルの中でしか使えません。なので、次のように書いて _sub.scss から$site-colorにアクセスしようとしてもエラーになります。

_sub.scss
@use "main";
.p-sub {
    background: variables.$site-color;    // エラー
    foreground: main.$site-color;         // これもエラー
}

また、@forward を使うことで、_variables.scss、_mixin.scss などのファイルで個別に定義されているグローバルな変数やミックスインなどを、ひとつのファイル (下の例では _defs.scss) に集約することができます (どうでもいいんですが「mixin」は「mixins」にすべきですかね?)。

_defs.scss
@forward "variables";
@forward "mixin";
@forward "functions";
_main.scss
@use "defs";
.p-main {
    background: defs.$site-color;
}

移行作業の実際

FLOCSS 的に考えて、対応が必要なのは次の 2 項目かと思います。

  • style.scss の @import を @use に変更する
  • グローバルな変数やミックスインを @forward で集約する

以下、それぞれ説明します。具体的なソースコードは GitHub にあるので必要に応じて参照してください。

style.scss の @import を @use に変更

変更前の sytle.scss は次のようになっていました。

style.scss (変更前)
@import "foundation/_foundation";
@import "layout/**";
@import "component/**";
@import "project/**";
@import "utility/**";

これをほぼそのまま @use に置き換えます。

style.scss (変更後)
@use "foundation";
@use "layout";
@use "component";
@use "project";
@use "utility";

変更前のコードで用いていた「なんちゃら/**」という記法は、そのディレクトリの下にあるすべてのファイルを、サブディレクトリまで含めて一括インポートすることのできる記法です。これ実は Sass 自体でサポートされているものではなく、 gulp-sass-glob という Gulp のプラグインを利用することで使えるようになる記法なんですね (当サイトの場合。同様のプラグインは他にもあるかもしれません)。

この手のプラグインを使えば @use でも同様の記法が使えるのかもしれませんが、プラグイン依存から脱却するため、この記法はやめることにしました。で、どうするかというと、Sass には「ディレクトリに _index.scss ファイルを作っておき、そのディレクトリ自身をロードすると _index.scss に書かれているファイルが自動的にロードされる」というルールがあります:

そこで例えば project ディレクトリに _footer.scss、_header.scss、_main.scss という 3 つのファイルがあったとしたら、project/_index.scss を作って次のように書きます。

project/_index.scss
@forward "footer";
@forward "header";
@forward "main";

あとは上のほうで示したように style.scss に「@use "project";」と書けば、project ディレクトリ配下にある各ファイルが自動的に sytle.scss にロードされます。

グローバルな変数やミックスインを @forward で集約する

変更前の sytle.scss では、まっ先に foundation/_foundation.scss を @import でロードしていました。で、その foundation/_foundation.scss は foundation レイヤにあるグローバル変数やミックスインを @import でロードしていました。

foundation/_foundation.scss (変更前)
@import "_variables";
@import "_mixin";
@import "_base";

つまり foundation/_foundation.scss のロード以降にロードされたすべてのファイルで、foundation レイヤで定義された変数やミックスインにアクセスすることができました。

ですが @use ルールのもとではそういうわけにいきません。上のほうでも書いたように、@use でロードしたモジュールは、そのファイルの中でしか使えないからです。そこで、グローバルスコープに置きたい変数やミックスインが定義されているモジュールを @forward を使って foundation/_defs.scss に集約し、それらのモジュールを使いたいファイルの側で _defs.scss をロードすることにしました。次のように書きます。

foundation/_defs.scss
@forward "variables";
@forward "mixin";
foundation/_variables.scss にある変数を読み出す例
@use "foundation/defs";
.p-header {
    background: defs.$site-color;
}

これで移行作業は終了です。と思ったんですが。

ついでに map-get

@import から @use / @forward への移行作業が終わり、やれやれと思ってコンパイルしたところ、まだなにか警告が残っていました。

Deprecation Warning [global-builtin]: Global built-in functions are deprecated and will be removed in Dart Sass 3.0.0.
Use map.get instead.

More info and automated migrator: https://sass-lang.com/d/import

  ╷
8 │     @media screen and #{map-get(v.$breakpoints-up, $bp)} {
  │                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵

map-get() は廃止予定であるから代わりに map.get() を使用せよとのことです。今までは単に map-get() を呼び出せば済んだんですが、これからは自作のモジュールと同様に、@use により sass:map モジュールをロードして使うことになるようです。

例えば次のように変更します。

foundation/_mixin.scss (差分)
- @use "variables" as v;
+ @use "sass:map";
+ @use "variables" as v;
  ...
-     @media screen and #{map-get(v.$breakpoints-up, $bp)} {
+     @media screen and #{map.get(v.$breakpoints-up, $bp)} {

以上です、お疲れさまでした!

広告