📘

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