Skip to content

Fixes #319 - Image optimization and basic caching - #321

Open
devyeyostellar wants to merge 2 commits into
AURORALAOrg:mainfrom
devyeyostellar:bounty-319-image-optimization
Open

Fixes #319 - Image optimization and basic caching#321
devyeyostellar wants to merge 2 commits into
AURORALAOrg:mainfrom
devyeyostellar:bounty-319-image-optimization

Conversation

@devyeyostellar

@devyeyostellar devyeyostellar commented Aug 11, 2026

Copy link
Copy Markdown

This PR implements the requirements for Issue #319 (OnlyDust Bounty):

  • Added vite-plugin-image-optimizer to package.json for automatic optimization of png, jpeg, jpg, webp during the build process.
  • Updated vite.config.js to configure the image optimizer plugin.
  • Added basic caching via Rollup output options (hashing asset filenames and splitting vendor chunks).

Summary by CodeRabbit

  • Performance
    • Images are now optimized during production builds, helping reduce asset sizes and improve loading times.
    • Build assets use stable, cache-friendly filenames to support faster repeat visits.
    • Application resources are better organized for more efficient delivery.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR adds Vite image optimization for common image formats. It also configures hashed asset names and groups node_modules dependencies into a vendor chunk.

Changes

Vite build asset handling

Layer / File(s) Summary
Image optimization setup
package.json, vite.config.js
Adds vite-plugin-image-optimizer and configures format-specific quality settings with lossless WebP handling.
Hashed build output and vendor chunking
vite.config.js
Configures hashed names for assets, chunks, and entry files. Groups node_modules dependencies into a vendor chunk.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related issues

  • AURORALAOrg/aurora-frontend issue 319: Adds the Vite image optimization requested by this issue.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the main changes and references Issue #319, but it omits the required type, proof, checklist, and additional notes sections. Use the repository template and complete the Type of Change, Proof of Completion, Checklist, and Additional Notes sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies image optimization and caching, which are the main changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 75-76: Add compatible sharp and svgo development dependencies
alongside vite-plugin-image-optimizer in package.json, then regenerate yarn.lock
so both packages and their resolved transitive dependencies are recorded.

In `@vite.config.js`:
- Around line 5-16: Add sharp and svgo as project dependencies required by
ViteImageOptimizer, and update the lockfile accordingly. Ensure the dependency
versions are compatible with vite-plugin-image-optimizer@1.1.7 so processing
both raster and SVG assets succeeds.
- Line 25: Update the asset build configuration around assetFileNames so hashing
occurs after image optimization, replacing or reconfiguring
vite-plugin-image-optimizer as needed. Ensure emitted asset filenames and all
references use hashes derived from optimized bytes, while preserving
Vite-inlined image behavior; add coverage that changing optimizer quality
changes both optimized output and its asset URL hash.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3677948e-d5e7-43e3-abbc-d0766dc20f38

📥 Commits

Reviewing files that changed from the base of the PR and between 56e4984 and 0293c68.

📒 Files selected for processing (2)
  • package.json
  • vite.config.js

Comment thread package.json
Comment on lines +75 to +76
"vite-bundle-visualizer": "^1.2.1",
"vite-plugin-image-optimizer": "^1.1.7"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

for dep in sharp svgo; do
  jq -e --arg dep "$dep" \
    '((.dependencies // {}) + (.devDependencies // {})) | has($dep)' \
    package.json >/dev/null
done

Repository: AURORALAOrg/aurora-frontend

Length of output: 165


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- manifests ---'
git ls-files '*package.json' '*lock*' '*yarn.lock' '*pnpm-lock.yaml' '*package-lock.json' | sort
printf '%s\n' '--- root package.json context ---'
cat -n package.json | sed -n '1,110p'
printf '%s\n' '--- engine references ---'
rg -n --glob '!node_modules/**' --glob '!dist/**' '\b(sharp|svgo|vite-plugin-image-optimizer)\b' .

Repository: AURORALAOrg/aurora-frontend

Length of output: 5079


🌐 Web query:

vite-plugin-image-optimizer 1.1.7 sharp svgo peerDependencies dynamic import README

💡 Result:

In version 1.1.7 of vite-plugin-image-optimizer, released on August 12, 2023, the plugin introduced a significant architectural change regarding its dependencies, sharp and svgo [1][2][3]. Key details include: Dynamic Imports: To support both CommonJS and ES module environments (such as vite.config.mjs), version 1.1.7 implemented dynamic imports for sharp and svgo [2][4]. This allows these heavy dependencies to be loaded on-demand rather than synchronously at startup [2]. Peer Dependencies: Because sharp and svgo are handled via dynamic imports, they are marked as optional peer dependencies [5][2]. This design decision enables users to install only the libraries they need—for example, skipping sharp if they only require SVGO, or vice versa [6]. Documentation and Requirements: The README emphasizes that sharp and svgo are not bundled with the plugin [6][7]. Users must install them manually as dev dependencies in their own projects [6][7]. For version 1.1.7, while explicit peer dependency ranges were defined in the package metadata, the core requirement is that these packages must be present in the user's environment for the corresponding features to function [2][6]. By treating these libraries as optional peer dependencies, the plugin avoids forcing unnecessary heavy dependencies on users who may not need the full suite of optimization features [6].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- vite.config.js ---'
cat -n vite.config.js
printf '%s\n' '--- lockfile engine entries ---'
rg -n -C 3 '^("?)(sharp|svgo)(@|:)|vite-plugin-image-optimizer' yarn.lock
printf '%s\n' '--- plugin metadata and README ---'
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/1.1.7 \
  | jq '{version: .version, dependencies: .dependencies, peerDependencies: .peerDependencies, peerDependenciesMeta: .peerDependenciesMeta}'
curl -fsSL https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/README.md \
  | rg -n -C 3 'sharp|svgo|default|include|exclude|matcher'

Repository: AURORALAOrg/aurora-frontend

Length of output: 1343


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf '%s\n' '--- npm metadata ---'
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/1.1.7 \
  | jq '{version: .version, dependencies: .dependencies, peerDependencies: .peerDependencies, peerDependenciesMeta: .peerDependenciesMeta}' || true

printf '%s\n' '--- README references ---'
curl -fsSL https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/README.md \
  | rg -n -C 4 'sharp|svgo|include|exclude|svg|png|jpeg|webp' || true

printf '%s\n' '--- v1.1.7 source candidates ---'
for path in src/index.ts src/index.js lib/index.js dist/index.js; do
  url="https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/$path"
  if body=$(curl -fsSL "$url" 2>/dev/null); then
    printf '\n### %s\n' "$path"
    printf '%s\n' "$body" | rg -n -C 5 'sharp|svgo|include|exclude|svg|png|jpeg|webp|dynamic' || true
  fi
done

Repository: AURORALAOrg/aurora-frontend

Length of output: 12839


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- lockfile references ---'
rg -n -C 2 'sharp|svgo|vite-plugin-image-optimizer' yarn.lock || true

printf '%s\n' '--- image assets ---'
git ls-files | rg -i '\.(svg|png|jpe?g|gif|tiff|webp|avif)$' || true

printf '%s\n' '--- optimizer configuration ---'
rg -n -C 4 'ViteImageOptimizer|test:|include:|exclude:|includePublic' --glob '!node_modules/**' --glob '!dist/**' .

Repository: AURORALAOrg/aurora-frontend

Length of output: 5255


Declare the image optimizer engines.

Add compatible sharp and svgo development dependencies and update yarn.lock. The default matcher processes the repository’s raster assets and SVG files, but neither engine is declared.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` around lines 75 - 76, Add compatible sharp and svgo development
dependencies alongside vite-plugin-image-optimizer in package.json, then
regenerate yarn.lock so both packages and their resolved transitive dependencies
are recorded.

Source: MCP tools

Comment thread vite.config.js
Comment on lines +5 to +16
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';

export default defineConfig({
plugins: [react()],
plugins: [
react(),
ViteImageOptimizer({
png: { quality: 80 },
jpeg: { quality: 80 },
jpg: { quality: 80 },
webp: { lossless: true },
})
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 2 'assetsInlineLimit|ViteImageOptimizer' vite.config.js
fd -HI -t f -e png -e jpg -e jpeg -e webp . \
  --exclude node_modules \
  --exclude dist

Repository: AURORALAOrg/aurora-frontend

Length of output: 1361


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- vite.config.js ---'
cat -n vite.config.js

printf '%s\n' '--- package manifests ---'
for f in package.json package-lock.json npm-shrinkwrap.json pnpm-lock.yaml yarn.lock; do
  if [ -f "$f" ]; then
    printf '\n[%s]\n' "$f"
    rg -n -C 3 'vite|vite-plugin-image-optimizer|sharp|pngquant|jpeg|webp' "$f" | head -160
  fi
done

printf '%s\n' '--- image references ---'
rg -n -C 2 '\.(png|jpe?g|webp)(\?[^"'\'']*)?["'\'']|/.*\.(png|jpe?g|webp)' --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' . | head -240

Repository: AURORALAOrg/aurora-frontend

Length of output: 17702


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- vite.config.js ---'
cat -n vite.config.js

printf '%s\n' '--- package manifests ---'
for f in package.json package-lock.json npm-shrinkwrap.json pnpm-lock.yaml yarn.lock; do
  if [ -f "$f" ]; then
    printf '\n[%s]\n' "$f"
    rg -n -C 3 'vite|vite-plugin-image-optimizer|sharp|pngquant|jpeg|webp' "$f" | head -160
  fi
done

printf '%s\n' '--- image references ---'
rg -n -C 2 '\.(png|jpe?g|webp)(\?[^"'\'']*)?["'\'']|/.*\.(png|jpe?g|webp)' \
  --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' . | head -240

Repository: AURORALAOrg/aurora-frontend

Length of output: 16152


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

printf '%s\n' '--- vite-plugin-image-optimizer package metadata ---'
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/1.1.7 \
  | jq -r '.dist.tarball, .dist.integrity'

tarball="$tmpdir/plugin.tgz"
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tarball"
mkdir "$tmpdir/package"
tar -xzf "$tarball" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- package files ---'
find "$tmpdir/package" -maxdepth 3 -type f -print | sort

printf '%s\n' '--- plugin hook and asset handling ---'
rg -n -C 5 'generateBundle|writeBundle|load|transform|emitFile|asset|public|inline|sharp|squoosh' \
  "$tmpdir/package" | head -260

printf '%s\n' '--- repository image sizes ---'
find public src/assets -type f \( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) -print0 |
  xargs -0 stat -c '%s %n' | sort -n

printf '%s\n' '--- JavaScript image imports ---'
rg -n -C 2 '(^|[^A-Za-z0-9_])import .* from ["'\''][^"'\'']+\.(png|jpe?g|webp)|(^|[^A-Za-z0-9_])import ["'\''][^"'\'']+\.(png|jpe?g|webp)' \
  --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' src

Repository: AURORALAOrg/aurora-frontend

Length of output: 18046


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

printf '%s\n' '--- vite-plugin-image-optimizer package metadata ---'
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/1.1.7 |
  jq -r '.dist.tarball, .dist.integrity'

tarball="$tmpdir/plugin.tgz"
curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tarball"
mkdir "$tmpdir/package"
tar -xzf "$tarball" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- package files ---'
find "$tmpdir/package" -maxdepth 3 -type f -print | sort

printf '%s\n' '--- plugin hook and asset handling ---'
rg -n -C 5 'generateBundle|writeBundle|load|transform|emitFile|asset|public|inline|sharp|squoosh' \
  "$tmpdir/package" | head -260

printf '%s\n' '--- repository image sizes ---'
find public src/assets -type f \( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) -print0 |
  xargs -0 stat -c '%s %n' | sort -n

printf '%s\n' '--- JavaScript image imports ---'
rg -n -C 2 '(^|[^A-Za-z0-9_])import .* from ["'\''][^"'\'']+\.(png|jpe?g|webp)|(^|[^A-Za-z0-9_])import ["'\''][^"'\'']+\.(png|jpe?g|webp)' \
  --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' src

Repository: AURORALAOrg/aurora-frontend

Length of output: 18046


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tmpdir/plugin.tgz"
mkdir "$tmpdir/package"
tar -xzf "$tmpdir/plugin.tgz" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- plugin implementation outline ---'
wc -c "$tmpdir/package"/dist/index.*
sed -n '1,220p' "$tmpdir/package/dist/index.mjs"

printf '%s\n' '--- plugin hook names ---'
grep -oE 'name:|buildStart|configResolved|resolveId|load|transform|transformIndexHtml|generateBundle|writeBundle|closeBundle|publicDir|includePublic|emitFile' \
  "$tmpdir/package/dist/index.mjs" | sort | uniq -c

printf '%s\n' '--- relevant README sections ---'
sed -n '83,115p' "$tmpdir/package/README.md"
sed -n '188,210p' "$tmpdir/package/README.md"

printf '%s\n' '--- image files and byte sizes ---'
find public src/assets -type f \( -iname '*.png' -o -iname '*.jpg' -o -iname '*.jpeg' -o -iname '*.webp' \) -print |
  while IFS= read -r f; do
    bytes=$(wc -c < "$f")
    printf '%s %s\n' "$bytes" "$f"
  done | sort -n

Repository: AURORALAOrg/aurora-frontend

Length of output: 10243


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tmpdir/plugin.tgz"
mkdir "$tmpdir/package"
tar -xzf "$tmpdir/plugin.tgz" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- complete plugin lifecycle implementation ---'
nl -ba "$tmpdir/package/dist/index.mjs" | sed -n '120,290p'

printf '%s\n' '--- all source image imports and CSS image URLs ---'
rg -n -C 2 'import[^;\n]*\.(png|jpe?g|webp)|url\([^)]*\.(png|jpe?g|webp)|src/assets/.*\.(png|jpe?g|webp)' \
  --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' .

printf '%s\n' '--- all files under public and src/assets ---'
find public src/assets -type f -print | sort

Repository: AURORALAOrg/aurora-frontend

Length of output: 255


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tmpdir/plugin.tgz"
mkdir "$tmpdir/package"
tar -xzf "$tmpdir/plugin.tgz" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- complete plugin lifecycle implementation ---'
cat -n "$tmpdir/package/dist/index.mjs" | sed -n '120,300p'

printf '%s\n' '--- all source image imports and CSS image URLs ---'
rg -n -C 2 'import[^;\n]*\.(png|jpe?g|webp)|url\([^)]*\.(png|jpe?g|webp)|src/assets/.*\.(png|jpe?g|webp)' \
  --glob '!node_modules/**' --glob '!dist/**' --glob '!*.lock' . || true

printf '%s\n' '--- all files under public and src/assets ---'
find public src/assets -type f -print | sort

Repository: AURORALAOrg/aurora-frontend

Length of output: 18904


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

curl -fsSL https://registry.npmjs.org/vite-plugin-image-optimizer/-/vite-plugin-image-optimizer-1.1.7.tgz \
  -o "$tmpdir/plugin.tgz"
mkdir "$tmpdir/package"
tar -xzf "$tmpdir/plugin.tgz" -C "$tmpdir/package" --strip-components=1

printf '%s\n' '--- optimizer peer dependencies ---'
cat "$tmpdir/package/package.json" | jq '{dependencies, peerDependencies, peerDependenciesMeta, optionalDependencies}'

printf '%s\n' '--- project optimizer dependencies ---'
rg -n -C 2 '"(sharp|svgo)"|^(sharp|svgo)@' package.json yarn.lock || true

printf '%s\n' '--- public processing implementation ---'
cat -n "$tmpdir/package/dist/index.mjs" | sed -n '290,355p'

Repository: AURORALAOrg/aurora-frontend

Length of output: 2298


Add sharp and svgo dependencies. vite-plugin-image-optimizer@1.1.7 dynamically imports both packages, but neither appears in package.json or yarn.lock. The build will fail when the plugin processes the existing raster and SVG assets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vite.config.js` around lines 5 - 16, Add sharp and svgo as project
dependencies required by ViteImageOptimizer, and update the lockfile
accordingly. Ensure the dependency versions are compatible with
vite-plugin-image-optimizer@1.1.7 so processing both raster and SVG assets
succeeds.

Source: MCP tools

Comment thread vite.config.js
build: {
rollupOptions: {
output: {
assetFileNames: 'assets/[name].[hash].[ext]',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 6 \
  'generateBundle|bundler\[filePath\]\.source' \
  node_modules/vite-plugin-image-optimizer

Repository: AURORALAOrg/aurora-frontend

Length of output: 318


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- tracked candidate files ---'
git ls-files | rg '(^|/)(vite\.config\.js|package\.json|package-lock\.json|npm-shrinkwrap\.json|yarn\.lock|pnpm-lock\.yaml)$'

printf '%s\n' '--- Vite configuration ---'
vite_cfg="$(git ls-files | rg '(^|/)vite\.config\.js$' | head -n 1)"
if [ -n "$vite_cfg" ]; then
  cat -n "$vite_cfg"
fi

printf '%s\n' '--- dependency declarations and lockfile references ---'
rg -n -C 4 'vite-plugin-image-optimizer|imageOptimizer|vite|rollup' \
  package.json package-lock.json npm-shrinkwrap.json yarn.lock pnpm-lock.yaml 2>/dev/null || true

printf '%s\n' '--- plugin references in tracked source ---'
rg -n -C 5 'ViteImageOptimizer|vite-plugin-image-optimizer|imageOptimizer' . \
  -g '!node_modules' -g '!dist' -g '!build' 2>/dev/null || true

Repository: AURORALAOrg/aurora-frontend

Length of output: 9271


🌐 Web query:

vite-plugin-image-optimizer v1.1.7 source generateBundle bundler[filePath].source Rollup asset hash timing

💡 Result:

In the context of vite-plugin-image-optimizer and similar Rollup-based plugins, the generateBundle hook operates on a bundle where asset file names and their associated hashes have typically already been resolved [1][2]. When the plugin attempts to modify an asset's content by updating bundler[filePath].source during this stage, it changes the actual file content without triggering a re-computation of the file's hash [1]. Because the file name (which often includes a [hash] placeholder) has already been determined by Rollup based on the original (pre-optimized) content, the final emitted file name will not reflect the changes made to the source content [1]. Key Technical Details: - Rollup's generateBundle Hook: By the time this hook is called, Rollup has already finalized the output manifest and resolved file names for all assets in the bundle [2]. - Asset Hashing Timing: Vite and Rollup resolve the [hash] placeholder based on the original asset content before it reaches the generateBundle hook [1]. Consequently, modifying the .source property at this late stage is effectively a "post-processing" step that updates the file content on disk but does not update the file name [1]. - Limitations: This behavior creates a disconnect where the optimized image content does not match the content-addressed hash in its filename [1]. This is a known limitation of using plugins that hook into generateBundle for asset optimization rather than performing transformations during earlier stages of the pipeline where Rollup's hashing logic still has the opportunity to react to content changes [1]. If you are encountering errors or unexpected behavior when modifying bundler[filePath].source, ensure you are correctly accessing the asset object. In some versions of vite-plugin-image-optimizer, improper access or attempts to modify non-asset bundle entries can lead to errors such as "Cannot set properties of undefined (setting 'source')" [3]. Official guidance often suggests that truly deterministic, hash-aware optimization requires specialized build-tool integration (like the proposed transformAsset hook in Rollup) that separates the emitting process from the transformation [1].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import json
import urllib.request

urls = [
    "https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/src/index.ts",
    "https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/package.json",
]
for url in urls:
    print(f"--- {url} ---")
    try:
        with urllib.request.urlopen(url, timeout=15) as response:
            print(response.read().decode())
    except Exception as exc:
        print(f"ERROR: {exc}")
PY

Repository: AURORALAOrg/aurora-frontend

Length of output: 645


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

fetch() {
  printf '%s\n' "--- $1 ---"
  curl -fsSLk --max-time 20 "$1"
  printf '\n'
}

fetch 'https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/src/index.ts'
fetch 'https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/package.json'
fetch 'https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/OutputBundle.ts'
fetch 'https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/Chunk.ts'

Repository: AURORALAOrg/aurora-frontend

Length of output: 11290


🏁 Script executed:

#!/usr/bin/env bash
set -u

for path in src/Bundle.ts src/Chunk.ts src/OutputAsset.ts src/OutputBundle.ts src/utils/FileEmitter.ts src/utils/RenderedSource.ts; do
  url="https://raw.githubusercontent.com/rollup/rollup/v4.46.2/$path"
  printf '%s\n' "--- $path ---"
  curl -fsSLk --max-time 20 "$url" 2>/dev/null || printf '%s\n' '(not found)'
done

printf '%s\n' '--- Rollup v4.46.2 source references for assetFileNames and hash resolution ---'
curl -fsSLk --max-time 30 \
  'https://api.github.com/repos/rollup/rollup/git/trees/v4.46.2?recursive=1' 2>/dev/null |
  jq -r '.tree[]?.path' |
  rg 'asset|fileName|hash|generateBundle' |
  head -n 120

Repository: AURORALAOrg/aurora-frontend

Length of output: 50383


🏁 Script executed:

#!/usr/bin/env bash
set -u

show_matches() {
  path="$1"
  printf '%s\n' "--- $path ---"
  curl -fsSLk --max-time 20 \
    "https://raw.githubusercontent.com/rollup/rollup/v4.46.2/$path" 2>/dev/null |
    rg -n -C 8 'finaliseAssets|hashPlaceholders|placeholder|assetFileNames|emitFile|source|generateBundle|renderChunks' |
    head -n 260 || true
}

show_matches src/utils/outputBundle.ts
show_matches src/utils/PluginDriver.ts
show_matches src/utils/FileEmitter.ts
show_matches src/utils/hashPlaceholders.ts
show_matches src/utils/renderChunks.ts

Repository: AURORALAOrg/aurora-frontend

Length of output: 22238


🏁 Script executed:

#!/usr/bin/env bash
set -u

printf '%s\n' '--- Rollup FileEmitter asset finalization ---'
curl -fsSLk --max-time 20 \
  'https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/utils/FileEmitter.ts' 2>/dev/null |
  sed -n '285,570p'

printf '%s\n' '--- Rollup renderChunks asset-related calls ---'
curl -fsSLk --max-time 20 \
  'https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/utils/renderChunks.ts' 2>/dev/null |
  rg -n -C 12 'finalizeAssets|setAssetSource|emitFile|asset|bundle\[|sourceHash' |
  head -n 320

Repository: AURORALAOrg/aurora-frontend

Length of output: 12922


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
import pathlib
import subprocess

def fetch(url):
    return subprocess.check_output(
        ["curl", "-fsSLk", "--max-time", "20", url],
        text=True,
    )

vite = pathlib.Path("vite.config.js").read_text()
assert "assetFileNames: 'assets/[name].[hash].[ext]'" in vite
assert "ViteImageOptimizer({" in vite

plugin = fetch(
    "https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/src/index.ts"
)
assert "generateBundle: async (_, bundler)" in plugin
assert "const source = (bundler[filePath] as any).source;" in plugin
assert "(bundler[filePath] as any).source = content;" in plugin

bundle = fetch(
    "https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/Bundle.ts"
)
assert bundle.index("hookSeq('generateBundle'") < bundle.index("this.finaliseAssets(outputBundle)")

emitter = fetch(
    "https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/utils/FileEmitter.ts"
)
assert "const sourceHash = getHash(consumedFile.source);" in emitter
assert "generateAssetFileName(" in emitter
assert emitter.index("sourceHash = getHash(consumedFile.source)") < emitter.index(
    "generateAssetFileName("
)

print("config uses a content hash in assetFileNames")
print("plugin v1.1.7 mutates emitted asset source in generateBundle")
print("Rollup hashes source and assigns the asset filename before generateBundle")
print("Rollup finalises assets after generateBundle")
PY

Repository: AURORALAOrg/aurora-frontend

Length of output: 254


🏁 Script executed:

#!/usr/bin/env bash
set -u

python3 - <<'PY'
import pathlib
import subprocess

def fetch(url):
    return subprocess.check_output(
        ["curl", "-fsSLk", "--max-time", "20", url],
        text=True,
    )

def check(label, condition):
    print(f"{label}: {'PASS' if condition else 'FAIL'}")
    return condition

vite = pathlib.Path("vite.config.js").read_text()
plugin = fetch("https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/src/index.ts")
bundle = fetch("https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/Bundle.ts")
emitter = fetch("https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/utils/FileEmitter.ts")

checks = [
    ("config hash pattern", "assetFileNames: 'assets/[name].[hash].[ext]'" in vite),
    ("optimizer configured", "ViteImageOptimizer({" in vite),
    ("plugin generateBundle hook", "generateBundle: async (_, bundler)" in plugin),
    ("plugin reads emitted source", "const source = (bundler[filePath] as any).source;" in plugin),
    ("plugin mutates emitted source", "(bundler[filePath] as any).source = content;" in plugin),
    ("generateBundle precedes finaliseAssets",
     bundle.index("hookSeq('generateBundle'") < bundle.index("this.finaliseAssets(outputBundle)")),
    ("asset hash is computed in setOutputBundle",
     emitter.index("const sourceHash = getHash(consumedFile.source);",
                   emitter.index("public setOutputBundle")) != -1),
    ("asset filename uses sourceHash",
     emitter.index("sourceHash, outputOptions", emitter.index("function generateAssetFileName")) != -1),
]

for label, passed in checks:
    check(label, passed)

if not all(passed for _, passed in checks):
    raise SystemExit(1)
PY

Repository: AURORALAOrg/aurora-frontend

Length of output: 271


🏁 Script executed:

#!/usr/bin/env bash
set -u

python3 - <<'PY'
import pathlib
import re
import subprocess

def fetch(url):
    return subprocess.check_output(
        ["curl", "-fsSLk", "--max-time", "20", url],
        text=True,
    )

def check(label, condition):
    print(f"{label}: {'PASS' if condition else 'FAIL'}")
    return condition

vite = pathlib.Path("vite.config.js").read_text()
plugin = fetch("https://raw.githubusercontent.com/FatehAK/vite-plugin-image-optimizer/v1.1.7/src/index.ts")
bundle = fetch("https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/Bundle.ts")
emitter = fetch("https://raw.githubusercontent.com/rollup/rollup/v4.46.2/src/utils/FileEmitter.ts")

set_output_bundle = emitter[
    emitter.index("public setOutputBundle"):
    emitter.index("private addOutputFileEmitter")
]
asset_name_function = emitter[
    emitter.index("function generateAssetFileName"):
    emitter.index("function getAssetFileName")
]

checks = [
    ("config hash pattern", "assetFileNames: 'assets/[name].[hash].[ext]'" in vite),
    ("optimizer configured", "ViteImageOptimizer({" in vite),
    ("plugin generateBundle hook", "generateBundle: async (_, bundler)" in plugin),
    ("plugin reads emitted source", "const source = (bundler[filePath] as any).source;" in plugin),
    ("plugin mutates emitted source", "(bundler[filePath] as any).source = content;" in plugin),
    ("generateBundle precedes finaliseAssets",
     bundle.index("hookSeq('generateBundle'") < bundle.index("this.finaliseAssets(outputBundle)")),
    ("asset hash is computed before asset naming",
     set_output_bundle.index("const sourceHash = getHash(consumedFile.source);") <
     set_output_bundle.index("this.finalizeAssetsWithSameSource")),
    ("asset filename hash uses sourceHash",
     bool(re.search(r"hash: size\s*=>\s*sourceHash\.slice", asset_name_function))),
]

passed = [check(label, condition) for label, condition in checks]
if not all(passed):
    print("--- relevant Rollup asset naming excerpt ---")
    print("\n".join(asset_name_function.splitlines()[35:55]))
    raise SystemExit(1)
PY

Repository: AURORALAOrg/aurora-frontend

Length of output: 457


Recompute asset hashes after image optimization.

vite-plugin-image-optimizer v1.1.7 mutates emitted asset source values in generateBundle, after Rollup generates the [hash] filename from the original source. The filename can therefore identify pre-optimized bytes. This affects emitted assets; Vite-inlined images bypass this hook.

Use an optimizer that runs before asset naming, or add a post-build hash and reference-rewrite step. Test that changing only optimizer quality changes both the optimized bytes and the asset URL hash.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vite.config.js` at line 25, Update the asset build configuration around
assetFileNames so hashing occurs after image optimization, replacing or
reconfiguring vite-plugin-image-optimizer as needed. Ensure emitted asset
filenames and all references use hashes derived from optimized bytes, while
preserving Vite-inlined image behavior; add coverage that changing optimizer
quality changes both optimized output and its asset URL hash.

Source: MCP tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant