Svelte + Vite環境でPurgeCSSを使う方法

目次

結論

  1. ViteはPostCSSと連携してくれるので、基本的にはpostcss.config.jspostcss-purgecssプラグインを指定するだけ。
  2. 追加でsafelistとして、[/^svelte-/, /^s-[0-9A-Za-z_-]{12}$/]を渡す。

経緯

Svelte + Vite + Tailwind CSSの場合、pnpm exec tailwindcss init -p1とかするだけで、Tailwind CSSが定義するCSSに関しては自動でいい感じにパージしてくれます。

tailwindcss init -pするとTailwind CSSが生成するCSSをパージする設定のpostcss.config.jsが生成され、またViteはPostCSSを自動で処理してくれる2からです。

しかし、.svelte内や、.scss内で@forとかして生成した大量のCSSはこれだけではパージされません。

Tailwind CSSがやっているように、PostCSSでPurgeCSSを使えばなんとかできそうなのでやってみました。

// postcss.config.js
export default {
  plugins: {
    '@fullhuman/postcss-purgecss': {
      content: [
        './src/**/*.svelte',
      ],
    },
  },
}

(設定ファイルは一般的な配列形式でなく、オブジェクト形式です。tailwindcss init -pが生成するのがそちらだったので。どちらでも大丈夫です。)

これでパージ自体は動きました。@forで大量のCSSを生成しても、使用しているもの以外はビルド時にパージされ、ファイルサイズが抑えられます。

しかし代わりに、Svelteのコンポーネント内で定義したCSSが削除されるという事象が発生しました。

調べてみたところ、CSSの適用をコンポーネント内に抑えるための、.svelte-xxxxxxxxのようなセレクタのCSS定義が削除されているようです。

これは、PurgeCSSの設定でこのようなセレクタをsafelistに入れてしまえばOKです。

// postcss.config.js
export default {
  plugins: {
    '@fullhuman/postcss-purgecss': {
      content: [
        './src/**/*.svelte',
      ],
      safelist: [
        /^svelte-/,
      ],
    },
  },
}

ちなみにこのsvelte-xxxxxxxxのような形式は、SvelteのcssHash3という名前のコンパイルオプションで変更可能なため、cssHashを設定している場合は適宜調整する必要があります。

また、この修正を行った後も、Viteの開発サーバでの動作時にはまだCSS定義が削除されていました。

開発サーバでの動作時は、なぜかsvelte-xxxxxxxxのような形式ではなく、s-xxxxxxのような形式になっていました。

svelte-xxxxxxxxに比べ短い上に誤爆しやすい接頭辞のため、cssHashで変更できないか試してみましたが、なぜかできません。

s-という文字列で元凶を探してみたところ、vite-plugin-svelte内にありました。vite-plugin-svelteでは、開発サーバで動作させる際のコンパイルオプションの調整が行われているようなのですが、そこでなぜか設定として渡したcssHashを無視して、自前の、s-xxxxxx形式のセレクタを生成する処理が設定されていました。

最終的に/^s-[0-9A-Za-z_-]{12}$/のような正規表現で、できる限り誤爆を抑えつつパージされないようにしました。

// postcss.config.js
export default {
  plugins: {
    '@fullhuman/postcss-purgecss': {
      content: [
        './src/**/*.svelte',
      ],
      safelist: [
        /^svelte-/,
        /^s-[0-9A-Za-z_-]{12}$/,
      ],
    },
  },
}

開発サーバでcssHashを設定できないことにはどうも理由があるようなので、これは修正されないでしょう。

vite-plugin-svelte/docs/faq.md at main · sveltejs/vite-plugin-svelte

Option to disable scoped CSS class hash in dev mode · Issue #872 · sveltejs/vite-plugin-svelte

下の方、なんか不穏なことも書いてますね。

Note that svelte5 is going to have integrated support for hmr and changes how css scoping works.

あるいは、開発サーバでの動作時はPurgeCSSを無効にするという方法も考えられます。個人的には開発サーバと本番ビルドでの差異はできるだけ小さくしたいため、今回は選択しませんでしたが。

この記事のライセンス

クリエイティブ・コモンズ・ライセンス

この文書はCC BY(クリエイティブ・コモンズ表示4.0国際ライセンス)で公開します。