Skip to content

Conversation

@JoeyC-Dev
Copy link
Contributor

@JoeyC-Dev JoeyC-Dev commented Feb 1, 2026

Type of change

  • Bug fix (a non-breaking change that fixes an issue)
  • New feature (a non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Other (please describe): Increase lighthouse score by enhancing page load speed

Checklist

  • I have read the CONTRIBUTING document.
  • I have checked to ensure that this Pull Request is not for personal changes.
  • I have performed a self-review of my own code.
  • My changes generate no new warnings.

Related Issue

Fix: #637 (comment)

Changes

  • Eliminate CDN requests for built-in Svelte icons by bundling only the 6 specific icons needed
  • Lazy-load PhotoSwipe only when images are present on the page
  • Optimize scroll/resize handlers with requestAnimationFrame and cached calculations
  • Add Vite build optimizations: minification, code splitting, vendor chunking, tree-shaking
  • Add DNS prefetch for Iconify API to reduce latency for social link icons
Too long

src/utils/preload-icons.ts:

  • Registers 6 icons used by Svelte components via addIcon() with official Iconify SVG data, preventing CDN fetches at runtime

src/components/misc/BrandIcon.svelte:

  • Svelte wrapper for @iconify/svelte Icon, used for social link icons in Profile widget (replaces astro-icon which cannot load icons dynamically from CDN)
    scripts/get-icon-data.js — Dev helper to fetch official icon data from Iconify API for adding new icons to preload-icons.ts

astro.config.mjs:

  • Restrict astro-icon include to only the specific icons used (was ["*"] for all sets)
  • Add Vite plugin to block all @iconify-json imports from being bundled (or the icon.js will be always 70+ KB)
  • Add vendor chunking: separate chunks for photoswipe, swup, overlayscrollbars, iconify, tailwind (Astro check warning)
  • Enable esbuild minification (actually enabled by default, but I just add it again), CSS code splitting
  • Set build target to esnext for aggressive tree-shaking (Aggressive improvement for mobile users)
  • Exclude @iconify-json packages from Vite dep optimization
  • Add inlineStylesheets: 'auto' for critical CSS inlining (slightly decrease mobile page load time)

src/layouts/Layout.astro:

  • Add DNS prefetch and preconnect for api.iconify.design
  • Import preload-icons.ts client-side before Svelte components initialize (for removing CDN)
  • Lazy-load PhotoSwipe: convert static import to dynamic import(), only load JS + CSS when images are detected on the page via document.querySelector
  • Replace PhotoSwipe close/zoom SVGs with official Material Symbols icons (for removing CDN, or it will be loaded when home page loaded)
  • Optimize scroll handler: cache viewport dimensions and thresholds, use requestAnimationFrame to batch DOM reads/writes, avoid forced reflows (lighthouse suggestion: render block)
  • Optimize resize handler: use requestAnimationFrame, recalculate cached thresholds
  • Batch CSS property writes to reduce layout thrashing
  • Strip onload animations after completion to prevent re-triggering during swup page transitions
  • Delay scrollbar init to after animations complete

src/components/widget/Profile.astro:

  • Replace astro-icon Icon with BrandIcon.svelte for social link icons (enables CDN loading for dynamic brand icons while keeping astro-icon for static icons)

tailwind.config.cjs:

  • Add hoverOnlyWhenSupported: true to prevent sticky hover states on touch devices

How To Test

Use lighthouse test service to test:
https://pagespeed.web.dev/

Remember to turn on brotli/gzip compression, and make sure the blog contains sufficient content for testing.

Screenshots (if applicable)

Details

Before:
before_desktop
before_mobile

After:
after_desktop
after_mobile


Details Before: image image

After:
image
image

Additional Notes

scripts/get-icon-data.js is the script that helps users obtain icons if they want to embed them, or provides developers with references to the icon SVGs.


Reason to eliminate bundled icons I specifically decide to move all icons for social links to CDN.

Currently, the size of /_astro/Icon.xxxx.js is 70+ KB (deflate) / 11 KB (brotli).
As we cannot predict how many icons the user will add, so I choose to only embed 6 icons which are hard-coded. For other requests, redirect them to CDN requests (with DNS prefetch).
After this change, the size become: 3.14 KB (deflate) / 0.1 KB (brotli).
image

Considered the file size is significantly reduced, this approach should be under consideration.


Chores

I was wondering why my blog was loading slower compared to others for a very long time, even though I am using the same template.
I compared some forks and blogs that use this template, and I found that most of the issues are due to the number of characters (not words) in each article being too high. This exacerbates the potential issues within this template.
I like this template, so I have no choice but to address the issue.
After fixing the animation reload issue (#720), the blog visually loads much faster, even though it doesn't have a high score in Lighthouse. This PR is the further improvement specifically for lighthouse testing.

If your blog does not contain many words in each article, there is no need to implement this PR. Visual improvement is not significant in this PR.


Missing banner

I was curious why banner is missing in my output, but looks like it is missing in current version (not due to my change): #681 (comment)

Click preview link, and you can find out that the banner is already missing in official build.
image


Upgrade to v6

Very interesting, after upgrading to v6.0.0-beta.6, the score is higher:
image
image

I have never seen a score of 99 on my blog. (and score for mobile is increased too)

So upgrading to v6 is important for reducing loading speed and should be taken into consideration. @saicaca

@vercel
Copy link

vercel bot commented Feb 1, 2026

@JoeyC-Dev is attempting to deploy a commit to the zephyirdgmailcom's projects Team on Vercel.

A member of the Team first needs to authorize it.

Signed-off-by: Joey Chen <142381267+JoeyC-Dev@users.noreply.github.com>
Comment on lines +229 to +230
output: {
manualChunks: (id) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This works in Astro v5 but not working in v6:

Cannot find module 'CD:\blog-fuwari\dist\.prerender\_astro\vendor.B-wHfxiC.js' imported from D:\blog-fuwari\dist\.prerender\prerender-entry.CjqpiJ7Y.mjs
  Location:
    D:\blog-fuwari\node_modules\.pnpm\@tailwindcss+node@4.1.18\node_modules\@tailwindcss\node\dist\esm-cache.loader.mjs:1:69
  Stack trace:
    at finalizeResolution (node:internal/modules/esm/resolve:274:11)
    at defaultResolve (node:internal/modules/esm/resolve:990:11)
    at o (file:///D:/blog-fuwari/node_modules/.pnpm/@tailwindcss+node@4.1.18/node_modules/@tailwindcss/node/dist/esm-cache.loader.mjs:1:69)
    at AsyncLoaderHooksOnLoaderHookWorker.resolve (node:internal/modules/esm/hooks:269:30)
    at [nodejs.internal.kHybridDispatch] (node:internal/event_target:845:20)
 ELIFECYCLE  Command failed with exit code 1.

manualChunks configuration here is creating separate vendor chunks during build that interfere with the prerender step in Astro v6. So this part needs to be removed if upgrading to v6.

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.

[Feature]: 添加博客内容懒加载

1 participant