Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
18e7033
バンドルアナライザー(通常はコメントアウトしてる
Mar 22, 2025
f8a98b0
Merge pull request #1 from hmochizuki/bundle-analize
hmochizuki Mar 22, 2025
7ff7b19
tree-shaking有効のためにwebpackの mode:none をコメントアウト
Mar 22, 2025
c7726d2
workspace のビルド設定を変更
Mar 22, 2025
dfe38bb
todo
Mar 22, 2025
58ee496
画像最適化と画像最適化スクリプト
onishi-precena Mar 22, 2025
a6fc534
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
76b9dde
createRoutes で設定されてる最小遅延時間を変更
Mar 22, 2025
d0f1bfa
lodashを削除、debounceの処理を追加
cOnigashima Mar 22, 2025
37a7de8
Merge pull request #2 from hmochizuki/onishi/delete_lodash
hmochizuki Mar 22, 2025
0c76a18
p-min-delayを削除した
cOnigashima Mar 22, 2025
d299b21
webpack の設定を少し修正
Mar 22, 2025
90369a4
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
9dc56da
Hoverableを改善(マウスのポインタを計算していたのをイベントリスナーにした)
cOnigashima Mar 22, 2025
50dab78
HomePageのコンポーネントたちを修正
cOnigashima Mar 22, 2025
676aef3
Merge pull request #3 from hmochizuki/main
cOnigashima Mar 22, 2025
9ff02a5
chore: update lock file
Mar 22, 2025
a9f68b5
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
127a398
useSubscribePointerがおかしかったので調整
cOnigashima Mar 22, 2025
aad834f
webpack に useExports: true 追加
Mar 22, 2025
35912c5
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
10b57fb
不要な行の削除
cOnigashima Mar 22, 2025
f843374
ssr で無駄っぽいのを削除
Mar 22, 2025
fe47538
main.js をdeferする
Mar 22, 2025
2b87684
HLS.jsの使い方を少し変更
cOnigashima Mar 22, 2025
fb13ee6
hydrationData の流し込み
Mar 22, 2025
bae49e0
gifを圧縮
cOnigashima Mar 22, 2025
00966e1
Revert "p-min-delayを削除した"
Mar 22, 2025
2ef87c3
update lock version
Mar 22, 2025
05a38d6
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
c8f913c
node_env を production に
Mar 22, 2025
0d7ee20
polyfillを削除した
cOnigashima Mar 22, 2025
700fd08
postTask(() => request, { delay: 1000 }); のdelayをやめる
cOnigashima Mar 22, 2025
0693043
schedule pluginを即時実行に、p-min-lazyを10msに
cOnigashima Mar 22, 2025
e2abdcc
fluent.jsonを剥がす
cOnigashima Mar 22, 2025
42035ee
ffmpeg を使わない
Mar 22, 2025
53f290f
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
ec7b9aa
`X-AREMA-INTERNAL="${randomBytes(3 * 1024 * 1024).toString('base64')}…
cOnigashima Mar 22, 2025
eb11acb
ssr を改善
Mar 22, 2025
4633fd9
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
f161b99
背景色が変わってる問題を修正
Mar 22, 2025
de0e4e9
create_playerでパフォーマンス最適化のための設定
cOnigashima Mar 22, 2025
fa172f8
<img> に loading='lazy' をつけてまわる
Mar 22, 2025
c0385b1
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
80f5bd5
AspectRatioとか多分いらない
cOnigashima Mar 22, 2025
07e3b85
seedデータのthumbnailUrlのバージョンパラメータを消した
Mar 22, 2025
6cd1f3f
webpack のチャンクを type: module にした
Mar 22, 2025
2c11c1c
useNativeHlsOnSafari をコメントアウト
Mar 22, 2025
015ce42
tsファイルを最適化したけど1%くらいしか変わらなかった(スクリプトだけ置いとく
Mar 22, 2025
819f699
bi, bx を剥がす(bxは使ってる箇所なさそうだった
Mar 22, 2025
ccfa1a4
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 22, 2025
d123b5d
Merge branch 'deploy-0322-1200' of https://github.com/hmochizuki/web-…
Mar 22, 2025
1b9649f
env を productionに変更
Mar 22, 2025
7122c54
fa-regular icon は使われてなさそうだった
Mar 22, 2025
6b35e4d
fa-solid アイコンを剥がした
Mar 22, 2025
5665434
スタイル修正
Mar 22, 2025
8c5e3ad
style
Mar 22, 2025
771e540
line-md アイコンを撲滅
Mar 22, 2025
781f914
line-md アイコンを撲滅
Mar 22, 2025
258f329
型エラー修正
Mar 22, 2025
40dd735
/recommended/error のエンドポイント作ってみた
Mar 22, 2025
d70f570
NotFoundPage でprefetchやめる
Mar 22, 2025
e498395
format
Mar 22, 2025
80aad64
無駄な直接処理を並列で実行
Mar 22, 2025
8e1dea0
ProgramページのprefetchをProgramだけにする(channels, timetables, modulesを除く)
Mar 23, 2025
f6dd03a
SeriesPageのprefetchをseriesだけにする(modulesをのぞく)
Mar 23, 2025
d4dbd80
NotFound でprefetch消す
Mar 23, 2025
9ed796b
EpisodePageのprefetch をepisodeのみにする(modulesなくす)
Mar 23, 2025
121f08c
Revert "ffmpeg を使わない"
cOnigashima Mar 23, 2025
6a94d2b
エラー画面のAPIを画面に最適化(いらないフィールドを削った
Mar 23, 2025
ba685a6
エラー画面のAPIを画面に最適化(いらないフィールドを削った
Mar 23, 2025
93da9b8
コメント削除
Mar 23, 2025
2a3274d
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
cOnigashima Mar 23, 2025
8076083
/recommend API のレスポンスを最適化(いらないフィールド削った
Mar 23, 2025
7917f32
Merge branch 'main' of https://github.com/hmochizuki/web-speed-hackat…
Mar 23, 2025
27650cd
SeriesEpisodeList のソートをやめる(サーバでやってる
Mar 23, 2025
a8f05ff
<img> に loading lazy をつけてまわる
Mar 23, 2025
0a78c01
jpegをavifに変換
Mar 23, 2025
dc3710e
jpegをavifに変換
Mar 23, 2025
9dc1854
Documentコンポーネントのprefetchやめる
Mar 23, 2025
e038e2d
Layout コンポーネントでもdーあるをlazy importしてるのをやめる
Mar 23, 2025
4cd24fc
シークバーのサムネイル表示ををサーバー側の処理に寄せる
cOnigashima Mar 23, 2025
9734be9
50枚に上げる
cOnigashima Mar 23, 2025
386bd5e
画像だけ入れておいて、generateはコメントアウト
cOnigashima Mar 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/image_optimizer.cpython-313.pyc
Binary file not shown.
33 changes: 33 additions & 0 deletions compress_gif.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env python3
import sys
import subprocess

def compress_gif(input_gif: str, output_gif: str, optimize_level=3, lossy=100, colors=128):
"""
gifsicle コマンドを使って GIF を圧縮する
:param input_gif: 入力 GIF ファイルパス
:param output_gif: 出力 GIF ファイルパス
:param optimize_level: 最適化レベル (1~3)
:param lossy: lossy 圧縮の強度 (0~100)
:param colors: 使用する色数 (1~256)
"""
command = [
"gifsicle",
f"--optimize={optimize_level}",
f"--lossy={lossy}",
f"--colors={colors}",
"-o",
output_gif,
input_gif
]
subprocess.run(command, check=True)

if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python compress_gif.py <input.gif> <output.gif>")
sys.exit(1)
input_gif_path = sys.argv[1]
output_gif_path = sys.argv[2]

compress_gif(input_gif_path, output_gif_path)
print(f"Compressed GIF saved to {output_gif_path}")
77 changes: 77 additions & 0 deletions image_optimizer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from PIL import Image
import os

input_dir = 'public/images'
output_dir = 'public/images_optimized'

def optimize_image(input_path, output_path, quality=60, resize_factor=None, convert_to_webp=False):
"""
画像を軽量化する関数

Args:
input_path: 入力画像のパス
output_path: 出力画像の保存先パス
quality: JPEG品質(0-100)
resize_factor: リサイズ比率(例:0.5で半分のサイズ)
convert_to_webp: WebP形式に変換するかどうか
"""
# 画像を開く
img = Image.open(input_path)

# RGBAの場合はRGBに変換
if img.mode == 'RGBA':
img = img.convert('RGB')

# リサイズ処理
if resize_factor and resize_factor > 0:
new_width = int(img.width * resize_factor)
new_height = int(img.height * resize_factor)
img = img.resize((new_width, new_height), Image.Resampling.LANCZOS)

# WebP形式に変換する場合
if convert_to_webp:
output_path = os.path.splitext(output_path)[0] + '.webp'

# 画像を保存(圧縮)
img.save(output_path,
optimize=True,
quality=quality)

# 実際に使用された出力パスを返す
return output_path

def batch_optimize_images(input_dir, output_dir, quality=60, resize_factor=None, convert_to_webp=False):
"""
フォルダ内の画像を再帰的に一括で軽量化する関数
"""
print(f"処理中のディレクトリ: {input_dir}")

if not os.path.exists(output_dir):
os.makedirs(output_dir)

for item in os.listdir(input_dir):
input_path = os.path.join(input_dir, item)
output_path = os.path.join(output_dir, item)

print(f"検出されたアイテム: {item}")

try:
if os.path.isdir(input_path):
print(f"フォルダを処理: {input_path}")
batch_optimize_images(input_path, output_path, quality, resize_factor, convert_to_webp)
elif item.lower().endswith(('.png', '.jpg', '.jpeg')):
print(f"画像を処理: {input_path}")
# 実際の出力パスを取得
actual_output_path = optimize_image(input_path, output_path, quality, resize_factor, convert_to_webp)

# 圧縮前後のファイルサイズを表示
original_size = os.path.getsize(input_path) / 1024
compressed_size = os.path.getsize(actual_output_path) / 1024
print(f'{item}:')
print(f' 圧縮前: {original_size:.1f}KB')
print(f' 圧縮後: {compressed_size:.1f}KB')
if resize_factor:
print(f' リサイズ: 元のサイズの{int(resize_factor * 100)}%')
except Exception as e:
print(f"エラー発生 - ファイル: {item}")
print(f"エラー内容: {str(e)}")
129 changes: 129 additions & 0 deletions jpeg-to-avif-ffmpeg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#!/usr/bin/env node

/**
* JPEG画像をAVIF形式に変換するスクリプト (ffmpeg使用版)
*
* このスクリプトは、指定されたディレクトリ内のJPEG画像ファイルをAVIF形式に変換します。
* 変換にはシステムにインストールされているffmpegを使用します。
* AVIF形式は次世代の画像圧縮形式で、優れた圧縮率と画質を持ちます。
*
* 使用方法:
* node jpeg-to-avif-ffmpeg.js
*
* 必要な環境:
* - ffmpeg がシステムにインストールされていること
*/

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');

// 設定パラメータ
const INPUT_DIR = 'public/images'; // 入力ディレクトリ(JPEGファイルが格納されているディレクトリ)
const OUTPUT_DIR = 'public/images'; // 出力ディレクトリ(同じディレクトリに出力)
const QUALITY = 60; // AVIF品質(0-63)、値が低いほど高品質、高いほど圧縮率が上がる

/**
* JPEG画像をAVIF形式に変換する関数
* @param {string} jpegPath - 変換するJPEG画像のパス
* @param {string} avifPath - 出力するAVIF画像のパス
* @returns {Object} - 変換結果
*/
function convertJpegToAvif(jpegPath, avifPath) {
try {
// ffmpegコマンドの構築
// -y: 既存ファイルを上書き
// -i: 入力ファイル
// -c:v libaom-av1: AV1コーデックを使用
// -crf: 品質(0-63、値が低いほど高品質)
// -b:v 0: ビットレートを自動調整
const cmd = `ffmpeg -y -i "${jpegPath}" -c:v libaom-av1 -crf ${QUALITY} -b:v 0 "${avifPath}"`;

// コマンド実行
execSync(cmd, { stdio: 'pipe' });

// ファイルサイズ情報を取得
const jpegStats = fs.statSync(jpegPath);
const avifStats = fs.statSync(avifPath);

// KB単位のサイズ
const jpegSize = jpegStats.size / 1024;
const avifSize = avifStats.size / 1024;

// 圧縮率を計算
const compressionRatio = (1 - avifSize / jpegSize) * 100;

console.log(`変換完了: ${path.basename(jpegPath)} → ${path.basename(avifPath)}`);
console.log(` 元のサイズ: ${jpegSize.toFixed(2)} KB`);
console.log(` AVIFサイズ: ${avifSize.toFixed(2)} KB`);
console.log(` 圧縮率: ${compressionRatio.toFixed(2)}%`);

return { success: true };
} catch (error) {
console.error(`エラー: ${jpegPath} の変換中にエラーが発生しました - ${error.message}`);
return { success: false, error };
}
}

/**
* ディレクトリ内のすべてのJPEG画像をAVIF形式に変換する関数
*/
function batchConvertDirectory() {
// 出力ディレクトリが存在しない場合は作成
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

// ディレクトリ内のファイル一覧を取得
const files = fs.readdirSync(INPUT_DIR);

// JPEG/JPGファイルのみをフィルタリング
const jpegFiles = files.filter(file => {
const ext = path.extname(file).toLowerCase();
return ext === '.jpeg' || ext === '.jpg';
});

if (jpegFiles.length === 0) {
console.log(`変換対象のJPEG画像が ${INPUT_DIR} に見つかりませんでした。`);
return;
}

console.log(`合計 ${jpegFiles.length} 個のJPEG画像を変換します...`);

// 変換開始時間を記録
const startTime = Date.now();

// 変換カウンター
let successCount = 0;
let errorCount = 0;

// 各ファイルを順番に変換
for (const jpegFile of jpegFiles) {
const jpegPath = path.join(INPUT_DIR, jpegFile);
const avifFile = path.basename(jpegFile, path.extname(jpegFile)) + '.avif';
const avifPath = path.join(OUTPUT_DIR, avifFile);

// 変換を実行
const result = convertJpegToAvif(jpegPath, avifPath);

if (result.success) {
successCount++;
} else {
errorCount++;
}
}

// 処理時間を計算
const elapsedTime = (Date.now() - startTime) / 1000;

// 結果を表示
console.log("\n変換処理が完了しました。");
console.log(` 成功: ${successCount} 個`);
console.log(` 失敗: ${errorCount} 個`);
console.log(` 処理時間: ${elapsedTime.toFixed(2)} 秒`);
}

// メイン処理を実行
console.log("JPEG画像をAVIF形式に変換するプロセスを開始します...");
batchConvertDirectory();
console.log("処理が完了しました。");
127 changes: 127 additions & 0 deletions jpeg-to-avif.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
#!/usr/bin/env node

/**
* JPEG画像をAVIF形式に変換するスクリプト
*
* このスクリプトは、指定されたディレクトリ内のJPEG画像ファイルをAVIF形式に変換します。
* AVIF形式は次世代の画像圧縮形式で、優れた圧縮率と画質を持ちます。
*
* 使用方法:
* node jpeg-to-avif.js
*
* 必要なライブラリ:
* - sharp: `npm install sharp`
*/

const fs = require('fs');
const path = require('path');
const sharp = require('sharp');

// 設定パラメータ
const INPUT_DIR = 'public/images'; // 入力ディレクトリ(JPEGファイルが格納されているディレクトリ)
const OUTPUT_DIR = 'public/images'; // 出力ディレクトリ(同じディレクトリに出力)
const QUALITY = 50; // AVIF品質(1-100)、値が低いほどファイルサイズが小さくなるが、画質は低下
const EFFORT = 7; // 圧縮の努力レベル(0-9)、値が高いほど処理に時間がかかるが圧縮率が向上

/**
* JPEG画像をAVIF形式に変換する関数
* @param {string} jpegPath - 変換するJPEG画像のパス
* @param {string} avifPath - 出力するAVIF画像のパス
* @returns {Promise} - 変換処理のPromise
*/
async function convertJpegToAvif(jpegPath, avifPath) {
try {
// AVIF形式に変換して保存
await sharp(jpegPath)
.avif({
quality: QUALITY,
effort: EFFORT
})
.toFile(avifPath);

// ファイルサイズ情報を取得
const jpegStats = fs.statSync(jpegPath);
const avifStats = fs.statSync(avifPath);

// KB単位のサイズ
const jpegSize = jpegStats.size / 1024;
const avifSize = avifStats.size / 1024;

// 圧縮率を計算
const compressionRatio = (1 - avifSize / jpegSize) * 100;

console.log(`変換完了: ${path.basename(jpegPath)} → ${path.basename(avifPath)}`);
console.log(` 元のサイズ: ${jpegSize.toFixed(2)} KB`);
console.log(` AVIFサイズ: ${avifSize.toFixed(2)} KB`);
console.log(` 圧縮率: ${compressionRatio.toFixed(2)}%`);

return { success: true };
} catch (error) {
console.error(`エラー: ${jpegPath} の変換中にエラーが発生しました - ${error.message}`);
return { success: false, error };
}
}

/**
* ディレクトリ内のすべてのJPEG画像をAVIF形式に変換する関数
*/
async function batchConvertDirectory() {
// 出力ディレクトリが存在しない場合は作成
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

// ディレクトリ内のファイル一覧を取得
const files = fs.readdirSync(INPUT_DIR);

// JPEG/JPGファイルのみをフィルタリング
const jpegFiles = files.filter(file => {
const ext = path.extname(file).toLowerCase();
return ext === '.jpeg' || ext === '.jpg';
});

if (jpegFiles.length === 0) {
console.log(`変換対象のJPEG画像が ${INPUT_DIR} に見つかりませんでした。`);
return;
}

console.log(`合計 ${jpegFiles.length} 個のJPEG画像を変換します...`);

// 変換開始時間を記録
const startTime = Date.now();

// 変換カウンター
let successCount = 0;
let errorCount = 0;

// 各ファイルを順番に変換
for (const jpegFile of jpegFiles) {
const jpegPath = path.join(INPUT_DIR, jpegFile);
const avifFile = path.basename(jpegFile, path.extname(jpegFile)) + '.avif';
const avifPath = path.join(OUTPUT_DIR, avifFile);

// 変換を実行
const result = await convertJpegToAvif(jpegPath, avifPath);

if (result.success) {
successCount++;
} else {
errorCount++;
}
}

// 処理時間を計算
const elapsedTime = (Date.now() - startTime) / 1000;

// 結果を表示
console.log("\n変換処理が完了しました。");
console.log(` 成功: ${successCount} 個`);
console.log(` 失敗: ${errorCount} 個`);
console.log(` 処理時間: ${elapsedTime.toFixed(2)} 秒`);
}

// メイン処理を実行
console.log("JPEG画像をAVIF形式に変換するプロセスを開始します...");
batchConvertDirectory()
.then(() => console.log("処理が完了しました。"))
.catch(error => console.error("エラーが発生しました:", error));
Loading