🎃

現場のフロントエンド開発環境を Dart Sass へマイグレーションする覚書

3 min read

はじめに

Sass の公式ドキュメントで 2020 年 10 月に LibSass の利用は非推奨 になり、Dart Sass の利用を推奨しています。そんな折、筆者が所属するフロントエンド開発チームでは LibSass を利用しており Dart Sass へ移行を進めました。本稿は LibSass から Dart Sass の移行についてご紹介します。本移行時の Dart Sass のバージョンは 1.32.7 になります。

LibSass の非推奨は『継続的にメンテナンスをするが、将来的に追加予定の CSS および Sass の新機能の互換性を担保しない』という意味になります。

Dart Sass の移行計画

Sass 開発者は 2019 年 9 月に新たなモジュールシステムを公開しました。従来 Sass は @import 経由でモジュールの再利用を実現していましたが、@import には問題点があるため新しいモジュールシステム登場以降は @use 経由でモジュールを再利用するように再設計されました。新しいモジュールシステムは下位互換性があり段階的に移行しやすくなっています。@import は Dart Sass のモジュールシステムのサポート開始から 1 年後(2021 年 10 月)に非推奨、その 1 年後(2022 年 10 月)に完全終了する計画になっています。

マイグレーション作業

本移行にあたり node-sass パッケージの削除、sass パッケージの追加を実施します。node-sass パッケージが LibSass、sass パッケージが Dart Sass に該当します。

node-sass パッケージの削除
$ yarn remove node-sass -D
sass パッケージの追加
$ yarn add sass -D

互換性

npm 経由でインストールした Dart Sass は Node Sass(LibSass)にほぼ互換性のある JavaScript API をサポートしますが、Dart Sass はパフォーマンス観点で fibers パッケージを利用する手段を提示されています。しかし、本移行には fibers パッケージの追加対応を含めておりません。理由は fibers パッケージが Node.js 16 以降と互換性がありません。また fibers パッケージを利用せずとも パフォーマンスに悪影響を及ぼさない ことが言及されています。

冪等性

筆者が所属するフロントエンド開発チームは Vue.js の単一ファイルコンポーネント(SFC)に CSS Modules を採用しています。CSS Modules は特性上、ビルドファイルの cascading 順序が担保されておらず、ビルドごとに差分が発生します。そのままでは Dart Sass 移行の差分が判断しにくいため PostCSS を利用した抽象構文木(AST)で差分比較しました。もしソースコードに興味がある人は下記の「CSS Modules ビルド後の宣言ブロック冪等性担保スナップショットテスト」を参照ください。

CSS Modules ビルド後の宣言ブロック冪等性担保スナップショットテスト

マイグレーション後の差分

本移行では前述のモジュールシステムへ書き換えず、シンプルに LibSass から Dart Sass 移行の差分を確認しました。

Unicode 文字

いくつかのスタイルシートにおいて content プロパティに Unicode 文字を利用しています。たとえば、三点リーダーは Unicode 文字で次のように指定しています。

"content": "\002026",

Dart Sass 移行後、Unicode 文字の予期せぬデコードによる差分が発生しました。この問題は issue で議論されており、現在(2021 年 8 月 5 日時点)Dart Sass は UTF-8 しかサポートしていないため解決に至っておりません。ちなみに Dart 言語自体が UTF-8 しかサポートしていないことに起因します。そこで暫定措置として次のような @function を新規作成することで本問題を回避しました。

@use "sass:string";

@function unicode($str) {
  @return string.unquote('"') + string.unquote(string.insert($str, '\\', 1)) + string.unquote('"');
}

小数点以下の桁数

LibSass と Dart Sass はデフォルトで小数点以下の桁数が異なります。LibSass は初期値が 5、Dart Sass は初期値が 10 になります。

// LibSass 小数点以下の桁数
line-height: 1.22222

// Dart Sass 小数点以下の桁数
line-height: 1.2222222222

デフォルトの桁数は LibSass のオプション precision で制御可能でしたが、Dart Sass は本オプションをサポートしておりません。サポート対象外の理由は 小数点以下の桁数の初期値がすべてのブラウウザに対して充分高い精度で設定されており、カスタマイズ可能にすればコード効率の大幅な低下に繋がる ことが言及されています。ゆえに本差分は移行前と比較して特別の影響を及ぼさないことが予想され未対応にします。

潜在的な構文エラーの顕在化

LibSass では未発生の構文エラーが Dart Sass 移行後に問題が浮き彫りになりました。具体的にはトップレベルの親セレクタ(&)の利用が参照エラーを発生する問題です。ちなみに親セレクタは Sass 独自のセレクタであり、ネストされたセレクタから外部セレクタを参照するために利用されます。詳細は公式ドキュメントを参照ください。

Dart Sass 1.33.0 以降、除算目的の / は非推奨になります。これは区切り目的の /(e.g. grid: auto-flow / 1fr;)の判断に複雑な発見的手法を使用していることに起因します。除算目的の / は Dart Sass 2.0.0 で廃止予定です。

https://twitter.com/toshimarnie/status/1399304650155778061

さいごに

本稿では筆者が所属するフロントエンド開発チームのプロダクトにおける Dart Sass の移行について紹介しました。前述した通り LibSass の利用は既に非推奨です。また Sass 開発チームの今後の計画では遅くても 2022 年 10 月に @import が利用できなくなります。まだ Dart Sass に移行されていない場合は本稿が一助になれば幸甚です。

Discussion

ログインするとコメントできます