🧊

Svelte(Kit)のScoped CSSで付与されるクラス名を変えたい

`svelte-9hyylu`みたいなやつ。

なんか冗長じゃない?これ削れば少しでもページ容量を減らせるのでは?的なモチベーション。

Svelte単体の場合

`compile()`という`.svelte`ファイルを処理する処理があり、そこに`cssHash()`というオプションがあるのでそれをいじる。

A function that takes a { hash, css, name, filename } argument and returns the string that is used as a classname for scoped CSS. It defaults to returning svelte-${hash(css)}
https://svelte.dev/docs#compile-time-svelte-compile

Docsによると、デフォルトの実装は、

function cssHash({ hash, css, name, filename }) {
  return `svelte-${hash(css)}`;
}

で、この`hash()`の実装はココ。

svelte/hash.ts at 11af8509242956d5414fd8dc3205a40855437ab5 · sveltejs/svelte · GitHub

だいたい、3文字から7文字のハッシュが取れるようになってそう。

ただこのオプションを自分で指定する機会はそうそうないはずで、だいたいはSvelteKitだったりViteだったりを経由することになるはず。

SvelteKit(vite-plugin-svelte)

この場合、

  • `vite.config.js`で指定する方法
  • `svelte.config.js`で指定し、それを`vite.config.js`で読む方法

この2つがあるけど、どちらにせよ、`compilerOpitons`の`cssHash()`を指定すれば、それが`svelte.compile()`に届くようになってる。

ひとつ注意としては、いわゆる`dev`モードではそれが無視されるという点。

https://github.com/sveltejs/vite-plugin-svelte/blob/1be016cf0c240bafcc643b1d6f0747e1b71f1871/docs/faq.md#why-cant-csshash-be-set-in-development-mode

無視してるコードはここ。

https://github.com/sveltejs/vite-plugin-svelte/blob/1be016cf0c240bafcc643b1d6f0747e1b71f1871/packages/vite-plugin-svelte/src/utils/compile.ts#L61-L65

本番ビルドではちゃんと反映される。

意義はあるか

10ページ以下くらいのシンプルなサイトでは、`_${hash(css).slice(-1)}`という2文字にすることで、581KBだった`build`ディレクトリが、580KBになった。1KB減った。

めちゃめちゃ規模が大きいならありそう、だが、雑に短くするとハッシュが衝突して表示が崩れるリスクがあるので、それを目視確認しながら地道に調整するのはなかなかに大変そうではある。

Scoped CSSも結局はDXのための仕組みなので、本気で容量を削りたいなら自分でCSSを書くしかないのだなあ。

ちなみに、Svelteのコンパイラの`hash()`関数は、そのまま使うと(接頭辞なしで)クラス名としてinvalidな文字列が出ることがあるらしい。奥が深い。

cssHash's hash() function may generate invalid CSS identifiers · Issue #6821 · sveltejs/svelte · GitHub