Blog

Astroのビルド後CSSファイルの名前にastroコンポーネント名をつける

この記事の対象者

ビルド後のCSSファイルを任意のファイル名にしたい人が対象です。
Githubとデプロイサーバーが連携しててプッシュしたら自動でビルドして公開するというフローではなく、
ビルドして、FTPソフトでアップロードするというフローで公開する…
もしくは、ビルド後のファイルを納品して、納品先でCSSを担当者が触る可能性がある
という場合に役立つかもしれません。

背景とやりたいこと

ビルド後のCSSファイル名はastro.config.mjsassetFileNamesによって設定できるのですが、デフォルトのプロパティを使っても、ページコンポーネント以外のコンポーネント名をつけることができませんでした。

どういう時にそれが必要なのかというと、共通のCSSを一枚とページごとのCSSを作成し、ビルド後にはその2つのcssファイルがlinkタグで読み込まれるようにしたいというケースです。

layouts/Layout.astro というコンポーネントにて、下記のように共通CSSのscssファイルをインポートしているとします。
import '@styles/style.scss'

このstyle.scssは下記のように、@forwardで各ファイルを読み込んだものとなっています。

@forward 'foundation/root.scss';
@forward 'foundation/variable.scss';
@forward 'foundation/reset.scss';
@forward 'foundation/global.scss';

//共通(細かいパーツ)
@forward 'parts/btn.scss';
@forward 'parts/title.scss';

//共通(案件毎の共通レイアウト component以上サイズ)
@forward 'components/footer.scss';
@forward 'components/header.scss';

assetFileNamesキーを使えば、ビルド後CSSの一定のカスタマイズは可能です。

例えば、すべてのCSSをstyle.scssに集めていて、style.cssという1つのファイルにしたい場合は
下記のように設定すると、style.cssというファイル名でビルドされます。

export default defineConfig({
  build: {
    inlineStylesheets: "never",
  },
  vite: {
    build: {
      rollupOptions: {
        output: {
          assetFileNames: (assetInfo) => {
            let extType = assetInfo.name.split('.').at(-1);
            if (/css/i.test(extType)) {
              return '[ext]/style[extname]';
            } else {
              return '[ext]/[name][extname]';
            }
          },
        },
      },
    },
  },
});

ファイル名を決めているのが下記の部分です。
return '[ext]/style[extname]';

もしpages/◯◯/index.astroに各ページのcssをimportしている場合は、style2.css, style3.css, style4.css... というように複数のCSSファイルがビルドされます。

ページごとに固有の名前がついて欲しい場合は、
return '[ext]/[name][extname]';

とすることができます。[name]には、pagesに作成したastroファイルの[フォルダ名-ファイル名]が入ります。

しかし、この方法ではpagesにないコンポーネント専用のCSSファイルは、自由に名前をつけることができません。
Layoutという、全体に効かせたいコンポーネントのCSSファイルを、style.cssという名前にしたい場合はどうしたら良いだろうというのが今回の背景です。

解決法

いろいろ試行錯誤しましたが、ビルド時にastroのコンポーネント名を取得するストレートな方法が見つからなかったので、別のアプローチとなっています。
若干無理やりだと感じる方もいると思いますので、自己責任で参考にしてください。

assetFileNamesのoriginalFileNameプロパティを活かせればよかったが…

assetFileNamesのコールバック関数のパラメータであるassetInfoには、originalFileNameというプロパティがあります。
https://rollupjs.org/configuration-options/#output-assetfilenames

おそらく同じような悩みであろう人達のissuesがありました。

これによると、originalFileNameは実装されているようなのですが、今回のケースではnullundefinedが返ってきてしまいました。

もし将来的にこのプロパティが使えるようになれば、Layout.astroのファイル名を取得して、それを使ってビルド後のCSSファイル名を決めることができると思われます。
それが一番スマートな解決先だと思います。

assetInfo.sourceを利用する

assetInfo.sourceには、ビルド後のファイルの内容が入っています。
これを使って、ビルド後のCSSファイル名を決めることができます。
style.scssの一番上に、下記コメントを追加します。

/*
buildOutputFile: 'style';
*/

buildOutputFileという文字列は任意の文字列です。クラス名などと被らないユニークな名前にする必要があります。

「style」は、ビルド後のCSSファイル名になります。
この「buildOutputFile:」という文字列をsourceの中から探し、値をファイル名として使うというロジックをastro.config.mjsassetFileNamesに書きます。

export default defineConfig({
  build: {
    inlineStylesheets: "never",
  },
  vite: {
    build: {
      rollupOptions: {
        output: {

          assetFileNames: (assetInfo) => {
            let extType = assetInfo.name.split('.').at(-1);
            if (/css/i.test(extType)) {
              //assetInfo.sourceの中から文字列を探して値を取得する
              let firstLine = assetInfo.source.split('\n').find((line) => line.includes('buildOutputFile:'));
              if (firstLine) {
                firstLine = firstLine.split('buildOutputFile:')[1].trim();
                //ダブルクォーテーションとセミコロンを削除
                firstLine = firstLine.replace(/['";]/g, '');
                return `[ext]/${firstLine}[extname]`;
              } else {
                //「-index」を削除したファイル名を取得
                const fileName = assetInfo.name.replace('-index', '');
                return `[ext]/${fileName}`;
              }
            } else {
              return '[ext]/[name][extname]';
            }
          },

        },
      },
    },
  },
});

こうすれば、scss側で好きなファイル名を指定できるようになります。

コメントを記載していないファイルは、ファイル名の「-index」を削除したものがビルド後のファイル名になるようにしています。
これは、pages/◯◯/index.astroのような個々のファイルに対しての処理です。
ファイル名のindexを削除することで、ビルド後のファイル名が◯◯.cssとなります。

この方法ではLayout.astroに限らず、Card.astroのようなパーツのコンポーネントも同じように専用のcssファイルを作ることができます。
ただし、あまり細かいコンポーネントごとにCSSファイルを作ると、ビルド後のCSSファイルがその分増えてしまい、linkタグの数が増えてパフォーマンスに影響が出る可能性があるので、細かいパーツのCSSにはやらない方が良いと個人的には思っています。

おすすめの記事 recommend blog

新着 new blog

github