Skip to content

[パフォーマンス] gzip圧縮・ブラウザキャッシュヘッダーの追加 #2374

@masaton0216

Description

@masaton0216

背景

PageSpeed Insightsのモバイルスコアが44点と低く、FCP: 23.8秒、LCP: 34.7秒と非常に遅い状態です。
現在 public/.htaccess にはURL書き換えルールのみで、gzip圧縮やブラウザキャッシュヘッダーが設定されていません。

アプリケーションコードの変更なしで、転送サイズを大幅に削減できる最もインパクトの大きい改善です。

調査結果

現状の問題点

  • public/.htaccess にはmod_rewriteのルールのみ存在
  • gzip/deflate圧縮が未設定のため、CSS/JSがそのままのサイズで転送される
  • ブラウザキャッシュヘッダーが未設定のため、再訪問時も毎回全アセットをダウンロードしている

転送サイズの比較(gzip圧縮前後の推定)

ファイル 現在 gzip後(推定) 削減率
app.js 532KB ~150KB ~72%
app.css 296KB ~45KB ~85%
connect.css 16KB ~4KB ~75%
707.js 20KB ~7KB ~65%

キャッシュバスティングの状況

ブラウザキャッシュヘッダー(1年)を追加する前提として、既存のキャッシュバスティング機構を調査しました。

問題なし

アセット種別 方式
app.js / app.css / wysiwyg.js / codemirror.js Mix versioning (?id=hash)
707.js / connect.css / option CSS ?version=filemtime()
テーマCSS/JS ?version=filemtime()
site.css / page CSS ?version=timestamp
FontAwesomeフォント / アイコン画像(app.css内) Webpackがハッシュ付与

要修正(キャッシュバスティングなし)

ファイル 問題
resources/views/errors/503.blade.php asset('css/app.css') でバージョンパラメータなし
resources/views/manual/common/layout_base.blade.php Bootstrap/jQuery/FontAwesome/manual.css 全てバージョンなし

実装手順

Step 1: gzip圧縮の有効化

ファイル: public/.htaccess

<IfModule mod_rewrite.c> の前に以下を追加:

<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    AddOutputFilterByType DEFLATE application/javascript application/x-javascript
    AddOutputFilterByType DEFLATE application/json
    AddOutputFilterByType DEFLATE image/svg+xml
    AddOutputFilterByType DEFLATE font/woff2 application/x-font-ttf application/x-font-opentype
</IfModule>

Step 2: ブラウザキャッシュヘッダーの追加

ファイル: public/.htaccess

<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType text/css "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType font/woff2 "access plus 1 year"
    ExpiresByType application/x-font-ttf "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/gif "access plus 1 year"
    ExpiresByType image/svg+xml "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
</IfModule>

Mix versioning(?id=hash)および ?version=filemtime() がキャッシュバスティングを担保するため、長期キャッシュでも安全です。

Step 3: 503エラーページのキャッシュバスティング修正

ファイル: resources/views/errors/503.blade.php

変更前:

<link href="{{ asset('css/app.css') }}" rel="stylesheet">

変更後:

<link href="{{ url('/') }}{{ mix('css/app.css') }}" rel="stylesheet">

Step 4: マニュアルページのキャッシュバスティング修正

ファイル: resources/views/manual/common/layout_base.blade.php

Bootstrap/jQuery/FontAwesome/manual.css に ?version=filemtime() パラメータを追加:

<link rel="stylesheet" href="{{$base_path}}css/bootstrap.min.css?version={{ filemtime(public_path('css/bootstrap.min.css')) }}">
<link rel="stylesheet" href="{{$base_path}}css/manual.css?version={{ filemtime(public_path('css/manual.css')) }}">
<link rel="stylesheet" href="{{$base_path}}font/css/all.min.css?version={{ filemtime(public_path('font/css/all.min.css')) }}">
<script src="{{$base_path}}js/jquery-3.6.0.min.js?version={{ filemtime(public_path('js/jquery-3.6.0.min.js')) }}"></script>
<script src="{{$base_path}}js/popper.min.js?version={{ filemtime(public_path('js/popper.min.js')) }}"></script>
<script src="{{$base_path}}js/bootstrap.min.js?version={{ filemtime(public_path('js/bootstrap.min.js')) }}"></script>

検証方法

  1. Chrome DevTools の Network タブで、レスポンスヘッダーに Content-Encoding: gzip が含まれることを確認
  2. CSS/JS ファイルの転送サイズが圧縮されていることを確認
  3. レスポンスヘッダーに Expires または Cache-Control が含まれることを確認
  4. サーバーに mod_deflatemod_expires が有効であることを確認(a2enmod deflate expires
  5. 一般ページ・管理画面が正常に動作すること
  6. 503エラーページ(メンテナンスモード時)でCSSが正常に読み込まれること
  7. マニュアルページでCSS/JSが正常に読み込まれること

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions