Astro(Vite):ビルド後のアセットをフォルダ分けして、納品しやすい構成にする
Astroの標準ビルドでは、全アセットが _astro/ フォルダに集約されます。
しかし実務では、「特定のフォルダ構成」や「CSS/JSの1本化」での納品を求められることが少なくありません。
本記事では、Rollupの設定を活用して、運用しやすく整理された形で出力する方法を解説します。
1. クイックスタート:環境構築
まずはベースとなるプロジェクトを作成します。
# 1. プロジェクトの作成
npm create astro@latest my-project
# 2. 移動して依存関係をインストール
cd my-project
npm install astro-html-beautifier astro-relative-links
今回導入した2つのパッケージは、納品物の「品質」と「汎用性」を高めるために重要な役割を果たします。
| パッケージ名 | 役割 | 導入する理由 |
|---|---|---|
| astro-html-beautifier | HTMLの整形 | Astroが出力するHTMLは、コンポーネント化の影響でインデントが乱れがちです。これを人間が読みやすい綺麗なインデントに整えます。 |
| astro-relative-links | パスの相対化 | 通常、Astroのパスはルート相対(/始まり)ですが、これを**相対パス(./始まり)**に変換します。これにより、どんな階層のサーバーに置いてもリンク切れが起きなくなります。 |
フォルダ構成の比較イメージ
- 標準ビルド: 全てが _astro/ にフラットに配置され、ファイル名もハッシュ化されていて人間には解読不能。
- 本記事の手法: assets/ 以下に目的別のフォルダが作られ、ファイル名から中身が推測できる状態。
2. 実装:astro.config.mjs の設定
画像・スタイル・スクリプトを、拡張子ごとにフォルダへ振り分ける設定を記述します。
import { defineConfig } from 'astro/config';
import htmlBeautifier from 'astro-html-beautifier';
import relativeLinks from 'astro-relative-links';
export default defineConfig({
site: 'https://example.com/',
build: {
assets: 'assets/scripts', // JSの基本出力先
},
vite: {
build: {
assetsInlineLimit: 0, // 0に設定することで<style>インライン化を強制解除
cssCodeSplit: false, // CSSを1つにまとめる
rollupOptions: {
output: {
// JSファイルの設定
entryFileNames: `assets/scripts/script_[hash].js`,
// 画像・CSS・その他資産の設定
assetFileNames: (assetInfo) => {
const rawName = assetInfo.names?.[0] ?? '';
// 画像ファイルの振り分け(-- を / に置換して階層化)
if (/\.(gif|jpeg|jpg|png|svg|webp|mp4)$/.test(rawName)) {
const name = rawName.replace(/--/g, '/');
return `assets/images/${name}`;
}
// CSSファイルの振り分け
if (/\.css$/.test(rawName)) {
return 'assets/styles/[name]_[hash].[ext]';
}
// その他(フォント等)
return 'assets/[name].[ext]';
},
},
},
},
},
integrations: [
relativeLinks(), // パスを相対形式に変換
htmlBeautifier({ // HTMLを整形
indent_size: 2,
indent_char: '\t',
}),
],
});
3. ディレクトリ構造を維持する「フォルダ階層ハック」
通常、Astro(Vite)でビルドを行うと、ソースフォルダにあった階層構造は無視され、アセットはフラットに出力されます。そこで、ファイル名に -- を含めることで、擬似的にフォルダ階層を復元させる工夫を施します。
「--」をフォルダ区切りに変換する仕組み
astro.config.mjs 内の assetFileNames に記述した以下のロジックが肝となります。
const name = rawName.replace(/--/g, '/');
return `assets/images/${name}`;
この処理により、ビルド時にファイル名の中の -- が / (パス区切り文字)として解釈され、物理的なフォルダが生成されます。
| 元のファイル名 | 出力後のパス |
|---|---|
| src/assets/images/common/common--logo.png | assets/images/common/logo.png |
| src/assets/images/top/top--hero.jpg | assets/images/top/hero.jpg |
開発時に common--... と長く命名するのは正直やや面倒です。
しかし、このルールを守るだけで以下の恩恵が得られます。
- 自動フォルダ仕分け: ビルド後に手作業でファイルを移動させる必要がなくなります。
- 納品規定の遵守: クライアント指定の「いつものフォルダ構成」をミスなく再現。
- リンク切れ防止: 命名規則がパスに直結するため、構造が予測しやすくなります。
「開発時の少しの工夫」で、「整理整頓された納品データ」 を自動生成するのがこの手法の狙いです。
4. 案件に合わせた「ハッシュ値」の切り替え
ブラウザキャッシュ対策が必要か、それとも管理のしやすさを優先するかで設定を使い分けます。
パターンA:キャッシュ対策を優先(ハッシュあり)
ファイル名にランダムな文字列を付与し、更新時に必ず最新を読み込ませます。
entryFileNames: 'assets/scripts/script_[hash].js',
assetFileNames: 'assets/styles/[name]_[hash].[ext]',
パターンB:運用性を優先(ハッシュなし)
「HTMLを直接編集するので、ファイル名を変えないでほしい」と言われた場合に最適です。
entryFileNames: 'assets/scripts/main.js',
assetFileNames: 'assets/[name].[ext]',
※この場合ファイル名が固定されるため、ブラウザに古いキャッシュが残りやすくなります。
html側でexample.jpg?v=1234のようにパラメータをつけるなど対策が必要になります。
5. astroファイルの修正、ビルド
今回は src/components/Welcome.astro に以下を追記してみます。
---
import logo from '../assets/images/common/common--logo.png';
---
<img src={logo.src} />
反映したら下記でビルドを実行します。
npm run build
標準の Astro ビルドと異なり、人間がメンテナンスしやすい「伝統的な Web 制作」のフォルダ構成が再現されます。
カスタマイズ後の出力構造(dist/ 内)
dist/
├── index.html # インデントが整えられ、パスは相対形式(./)
└── assets/
├── images/ # 「--」を「/」に置換して階層化
│ ├── common/
│ │ └── logo.png
│ └── top/
│ └── hero.jpg
├── scripts/
│ └── script_a1b2c3d.js # JSをここに集約
└── styles/
└── index_e5f6g7h.css # 全CSSを1本化
構造のポイント
-
assets/ への集約: デフォルトの
_astro/ではなく、一般的な名称である assets/ に全リソースがまとまります。 -
フォルダ階層の復元:
src/assets/images/common--logo.pngというファイル名が、ビルド後にはassets/images/common/logo.pngという物理フォルダ構造に変換されています。 -
相対パスの保証:
astro-relative-linksの効果により、index.htmlからは./assets/...、下層ページのabout/index.htmlからは../assets/...として書き出されるため、サーバーのどの階層にアップロードしても表示崩れが起きません。
この構造であれば、納品後に「ここの文言ちょっと変えておいて」と頼まれた担当者が、ビルド環境なしでファイルを修正することも十分に可能です。
まとめ:Astroを使いつつ、納品ルールに合わせる
今回の対策で以下のことが可能になりました。
- コードの見た目: htmlBeautifier で、機械的なコードを読みやすく整形。
- パスの解決: relativeLinks で、どこに置いてもリンク切れしないデータに。
- 管理のしやすさ: 「--」ハックとJS集約で、納品後のファイル修正を楽に。
「ツールは便利に使いつつ、成果物は相手の要望(フォルダ構成など)にしっかり合わせる」。
そんな、現場での「やり取りをスムーズにする」ためのカスタマイズのご紹介でした。
Discussion