Astroのビルド後CSSファイルの名前にastroコンポーネント名をつける
この記事の対象者
ビルド後のCSSファイルを任意のファイル名にしたい人が対象です。
Githubとデプロイサーバーが連携しててプッシュしたら自動でビルドして公開するというフローではなく、
ビルドして、FTPソフトでアップロードするというフローで公開する…
もしくは、ビルド後のファイルを納品して、納品先でCSSを担当者が触る可能性がある
という場合に役立つかもしれません。
背景とやりたいこと
ビルド後のCSSファイル名はastro.config.mjs
のassetFileNames
によって設定できるのですが、デフォルトのプロパティを使っても、ページコンポーネント以外のコンポーネント名をつけることができませんでした。
どういう時にそれが必要なのかというと、共通の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
は実装されているようなのですが、今回のケースではnull
やundefined
が返ってきてしまいました。
もし将来的にこのプロパティが使えるようになれば、Layout.astro
のファイル名を取得して、それを使ってビルド後のCSSファイル名を決めることができると思われます。
それが一番スマートな解決先だと思います。
assetInfo.sourceを利用する
assetInfo.source
には、ビルド後のファイルの内容が入っています。
これを使って、ビルド後のCSSファイル名を決めることができます。
style.scssの一番上に、下記コメントを追加します。
/*
buildOutputFile: 'style';
*/
buildOutputFile
という文字列は任意の文字列です。クラス名などと被らないユニークな名前にする必要があります。
「style」は、ビルド後のCSSファイル名になります。
この「buildOutputFile:」という文字列をsourceの中から探し、値をファイル名として使うというロジックをastro.config.mjs
のassetFileNames
に書きます。
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にはやらない方が良いと個人的には思っています。