Blog Refactoring——From Hexo to Astro
This blog was translated by Mimo-V2.5 at 2026.6.15
The repository is now open-sourced: mocusez/astro-astrofly
At 2026.4.2, features have stabilized, welcome to try it out!
Origin
Since I started writing blog posts in my senior year of high school (late 2019), I’ve always used Hexo as my static blog generator. The blog themes I used were the beginner-friendly hexo-theme-next and later hexo-theme-butterfly.
Although Hexo has always met my blogging needs well, I have to admit it doesn’t satisfy my technical vanity: it’s not based on TypeScript (though Hexo didn’t officially switch to TypeScript until version 7.0 in 2023), doesn’t use Vite, and certainly doesn’t leverage modern frontend technologies like Tailwind CSS (atomic CSS solution), Vue, or React (though both are great, I still prefer Vanilla JS for small projects).
Customizing components was also quite difficult—my understanding of Hexo was limited to just using it; I didn’t understand how it worked under the hood.
The reason I delayed refactoring was that it wouldn’t bring significant benefits:
First, while building your own wheel has advantages in bundling and loading speed, implementing all the page routing functionality requires rethinking and rebuilding from scratch—I only started getting familiar with frontend development during my sophomore year, when I had to learn WeChat Mini Program development and Vue 3 to finish an innovation project, and Vue 2 through the BlueWhale Cloud project. My actual time learning frontend development hasn’t been that long.
Second, CSS is powerful but hard to master. Once you start writing it yourself, you’ll realize that creating good-looking CSS that dynamically adapts to different screen sizes isn’t simple at all. Both Hexo themes I used handled responsive design quite well, which seems almost incredible looking back.
Finally, academic pressure was an unavoidable burden. Obviously, refactoring a blog wouldn’t improve my GPA. Everyone was busy chasing grades and various school competitions—I was no exception. Refactoring a blog was just a personal interest—nobody wants to work on a bottomless project during time that should be spent having fun.
In summary, refactoring my blog during my undergraduate years was an impossible task.
Until 2024—I graduated! Forget about academic pressure; that’s no longer relevant.
Modern LLM models can now solve the first two problems: using GitHub Copilot or Cursor, anyone who knows how to use LLMs can create good-looking CSS and dynamically responsive web pages.
Now, I faced the need for i18n to better communicate with international peers. On this front, Hexo’s i18n solutions were unsatisfactory. Although the hexo-theme-butterfly official demo site has i18n, there were no related tutorials or examples. The online implementation approaches were overly clever hacks—better to start fresh than to wrestle with those.
And now I have far more time available than during my undergraduate years.
So, the blog refactoring plan was put on the schedule.
Framework Selection
Since we’re refactoring, technology selection is necessary. My planned technical requirements were:
- Support i18n for writing articles in English for future research
- Support modern frontend bundling (Vite, RSbuild, etc.) to improve initial load speed
- Easy migration from Hexo
Regarding static vs. dynamic pages, I deliberated for a long time: static pages can better utilize CDN (though I later realized that with Vite, the web design paradigm has changed—everyone now prefers bundling JS, but static pages are indeed easier to deploy), while dynamic pages save page generation time. The final decision was: static pages first, with consideration for dynamic pages if they offer particularly useful features.
Single Page Applications SPA (Vue & React)
I don’t have a great impression of SPAs: I encountered many pitfalls with routing when learning Vue. I’m also not satisfied with how SPAs handle routing—avoid them if possible. Pass.
Nuxt3
I encountered Nuxt3 during my sophomore year (2022). Vue + SSR was indeed attractive, but despite many tutorials, there wasn’t a good blog template. I couldn’t find any blog examples that effectively supported i18n online. Pass.
VitePress
VitePress was a project I’d been following—a replacement for VuePress with nice Vue + SSG features and documentation as solid as Vue’s.
But it only officially released 1.0 in March 2024, meaning there weren’t many good blog templates available online when I started refactoring. Although it officially supports i18n, I didn’t see any best practice examples. Still pass.
Next.js
React’s SSR solution—I built a demo with Next.js 14 during my internship, and the page results were pretty good: Tiqqun-demo
Next.js has a rich ecosystem with many Markdown-to-SSR examples, and there are不少 i18n implementation examples online (even with Tailwind support):
tailwind-nextjs-starter-blog-i18n
My concern was that the framework feels somewhat bloated. During my internship, I had issues with browser caching that caused problems, which lowered my impression a bit.
Without Astro, I would definitely have chosen Next.js.
Astro
While browsing V2EX, I find many users recommending this. Many people online had migrated from Hexo to Astro with numerous tutorials and good experiences. There are many tutorials and templates for implementing i18n.
On GitHub, I found HsuBlog—a solution I liked, but it didn’t seem to be compatible with Astro V4. That template just wouldn’t work for me.
Compared to various Vue and React solutions, Astro supports direct development with Vanilla JS—meaning I could directly reuse Hexo code without spending time converting programming logic between Hexo and Vue or React. This was great!
Astro also effectively handles RSS generation and SiteMap generation.
If you want to use Vue or React, Astro Islands can provide support.
TypeScript was also a headache, but Astro V4 can be configured to not use Strict mode by default, reducing the mental burden of development.
Astro can do SSG, and can be converted to SSR if necessary—so if the blog grows large and compilation times become too long, you can write your own backend to implement SSR.
A custom Astro component made by a netizen looks great: Custom Astro Component Sample
Easy to learn, supports Vite bundling, with huge future development potential—perfect, let’s use it!
Development Log
Astro, start!
pnpm create astro@latestpnpm astro add vue # Add if you want Vuepnpm add @astrojs/rssDevelopment plan:
Using hexo-theme-butterfly 5.1.0 as the template for development:
- hexo-theme-butterfly uses Stylus as the CSS solution—keeping all of it
- Preserving hexo-theme-butterfly’s page structure
The first problem to solve: how to convert from hexo-theme-butterfly’s Pug to Astro.
Although an enthusiastic contributor proposed using Pug in Astro in April 2024, with a related RFC from 2021, unfortunately no developers have followed up:
Add first-class support for Pug in .astro files
RFC: Add first-class support for Pug in .astro files
My solution: use GitHub Copilot to convert Pug.
The results were actually quite good—most of the code could be converted, though content related to reading Hexo-specific data needed manual adjustment.

Post Generation
Using the Collection API to import Markdown into Astro Collections, Astro reads the Markdown frontmatter for the next generation step.
Astro V5 uses a new Collection API. For specific implementation details, see: refactor: upgrade to Astro V5
Code Display Optimization
Adding line numbers and one-click code copy.
After installing astro-expressive-code, it should take over Shiki’s functionality by default:
pnpm add -D astro-expressive-code @expressive-code/plugin-collapsible-sections @expressive-code/plugin-frames @expressive-code/plugin-line-numbersDue to astro-expressive-code (as of 2024.12.28) not supporting LangAlias parameter passing #278, I had to temporarily give up and use Astro’s built-in Shiki for rendering
The 0.39.0 version updated on 2025.1.10 now supports
LangAliasparameter passingThis blog has updated the related styles: commit
If you want to add line numbers using Astro’s built-in Shiki, refer to these two links:
Adding Line Numbers to Astro’s Syntax Highlighting Using CSS
If you want to add syntax highlighting for languages not in Shiki’s list, see my other article:
How to Add MLIR and LLVM IR Syntax Highlighting to Your Blog
Table of Contents (TOC)
My current solution was generated by Claude 3.5, but it doesn’t feel very smart. If I get the chance, I plan to try these solutions:
Astro Blog Implementation of TOC
Astro Article Search, Creating a Simple Search Component
Comment System (Waline)
Since hexo-theme-butterfly already had a reserved spot for comments by default, the integration process went smoother than expected:
src/layout/additional-js.astro
<script type="module"> import { init } from 'https://unpkg.com/@waline/client@v3/dist/waline.js'; (() => { init({ el: '#waline-wrap', serverURL: "${serverURL}", pageview: true, dark: 'html[data-theme="dark"]', path: window.location.pathname, comment: true, }); })();</script>For old comments, I had to manually change the comment URLs in the database—there really wasn’t a better way.
Also upgraded the Waline server from V2 to V3, which went very smoothly.
But this doesn’t feel like a great solution—might improve it later.
2026.04.02: The Waline component has now been bundled into the build, no longer requiring CDN loading.
FancyBox (Pending)
https://fancyapps.com/fancybox/getting-started/
Haven’t found a suitable integration solution yet. The Hexo approach doesn’t seem to work.
Adding FancyBox Support to Your Blog
But if you want to implement it yourself, check this out:
https://github.com/SaintSin/astro-pandabox
Search System (Pending)
MeiliSearch solution: Astro Integration with Self-Deployed MeiliSearch
Simple Astro solution: Astro Article Search, Creating a Simple Search Component
Side Note
During technology selection, I discovered this Hexo theme that supports Vite bundling: hexo-theme-aurora
The effect felt a bit too fancy, and I’d already decided to refactor, otherwise it could have been worth considering.
While writing this article, I discovered that a blogger from my blogroll had also converted from Hexo to Astro and open-sourced their template: astro-antares
Looks pretty good—feel free to check it out if you’re interested.
Upgrading to Astro V5
I started refactoring during the week of October 30th, when Astro V5 wasn’t yet stable. By December 26th, when I added TOC and the Waline comment system, Astro V5 had already been officially released (2024.12.3). There was no reason not to upgrade.
pnpm dlx @astrojs/upgradeReference documentation: Upgrade to Astro v5
Features:
Astro v5.0 upgrades to Vite v6.0 as the development server and production bundler.
Great!
I encountered many issues during the upgrade—many old blog posts from 2019-2020 failed Zod validation. After fixing the old files, the upgrade went smoothly.
If strict format validation is required, I’d rather write Rust! Having so many standards to follow just for a simple application.
Second Refactoring—Upgrading to Astro V6 (2026.04.02)
The rapid development of LLMs has made frontend work incredibly simple. Tasks that once seemed troublesome are now handled by Claude Opus in one go.
Many effects I wanted to implement in 2024 were achieved in this update:
- JavaScript to TypeScript—without LLMs, I definitely wouldn’t have done this
- Stylus to Tailwind—Hexo’s Stylus was written very complexly, now directly resolved
- Waline and typed directly bundled—my skills were lacking back then, but it doesn’t matter now
- Adding PWA support—wanted to do this with Hexo but didn’t understand it at all, now with Opus just go for it
- Some aesthetic style adjustments
In 2025, Cloudflare acquired Astro and released the V6 upgrade at the end of 2025. Taking advantage of this minor refactoring to resolve it all together.
Now very much looking forward to Astro’s future development.
Conclusion
The entire refactoring process took about a week. Using hexo-theme-butterfly’s CSS saved me the time of worrying about styling.
The result is just usable—it still feels like something’s missing. Many of the original hexo-theme-butterfly features haven’t been implemented yet.
For this, I can only say that when I have time and interest, I’ll slowly add them in.
