How We Replaced Vue 2 with Alpine.js to Simplify Our Website and Boost Performance
A real-world case study of migrating from Vue 2 to Alpine.js to cut bundle size, improve performance, and streamline frontend development.
About me and Why We Did It?
Have you ever hesitated to update your website’s core technology, perhaps anxious about unexpected bugs, downtime, or the daunting task of retraining your team on new tools? Worried that one wrong step could stop leads from flowing and negatively impact your business? We felt exactly the same before transitioning our large, static Jekyll site (a static site generator that builds websites from plain text and templates) from Vue 2 to Alpine.js. This blog shares our journey, challenges, solutions, and why this move turned out to be one of our best decisions yet.
Hi, I'm Shreyash Mogaveera, a Web Developer 1 at Fyle. Our website is a large static Jekyll project with multiple resource pages, pricing pages, and 7–8 different lead generation forms, each with distinct purposes. Over time, our Vue 2 setup became an outdated and heavy overkill for these straightforward functionalities. Our team decided it was time for a change to improve performance and maintainability. This successful migration was a team effort. Garvit Singhal significantly contributed by writing validators and preparing extensive end-to-end tests to ensure our forms worked perfectly. My manager, Abhishek Jain, supported and trusted our initiative, guiding us through this transition. Shubham Bhansal was invaluable in thoroughly testing and identifying any potential breaking changes alongside our manager.
Why We Chose Alpine.js
Before settling on Alpine.js, we explored other options, including continuing with Vue 2 or upgrading to Vue 3, using Stimulus.js, or even adopting plain vanilla JavaScript.
Vue 3: We considered upgrading from Vue 2 to Vue 3 for better performance and long-term support. However, the migration was non-trivial and would require a large refactor across the site with minimal real benefit for our use case.
Stimulus.js: Stimulus offered a lightweight and modern approach, but its syntax felt too abstract for our team, and it lacked the reactive simplicity we liked about Vue.
Vanilla JavaScript: We briefly considered refactoring everything into plain JavaScript. However, that would have meant writing and maintaining a lot of boilerplate code, which would defeat our goal of simplifying the site.
In contrast, Alpine.js provided exactly what we needed:
Lightweight (~10KB)
Reactive and declarative like Vue: Alpine allows you to bind data to the DOM and automatically update the view when data changes, using intuitive syntax similar to Vue’s directives (e.g.,
x-data
,x-model
,x-show
). This makes it easy to build dynamic UI interactions without the complexity of a full framework.Easy to integrate with our existing Jekyll + Bootstrap setup
No build step required
Alpine allowed us to enhance interactivity directly within our HTML without the need for complex frameworks or heavy tooling. It was the perfect balance of simplicity and power for our static site.
Our website initially used Vue 2 extensively, coupled with plugins like vue-validator. Although powerful, Vue 2 brought heavy JS bundles, complicated dependencies, and maintenance challenges. Alpine.js emerged as the ideal solution: lightweight, easy to learn, and perfect for enhancing our static site’s interactivity.
Preparing for Change
Before diving into the migration, I spent around a week researching various alternatives to replace Vue 2, finally deciding on Alpine.js. We performed a thorough audit of our site to map out which components were using Vue and what our priorities should be:
Resource pages: Targeted first, we replaced Vue-based components and toggle buttons in the pricing page and resource pages within 2–3 days.
Forms: Around 7–8 forms were interconnected and bundled into a single large JS file. We realized forms had to be migrated together.
We decided to proceed carefully, starting with simpler elements to build confidence.
Step-by-Step Migration
The entire migration project was broken down into careful, manageable stages over the span of approximately three weeks. We intentionally started with non-critical components to test our Alpine.js implementation and to minimize risk. After the success of the first stage, we tackled the more complex and business-critical elements.
Our initial targets were the resource page components and toggle buttons on the pricing page. This stage only took 2–3 days to complete. However, the form migration, which affected 7–8 highly interconnected forms across our website, took approximately 1.5 weeks. We spent extensive time on staging with thorough manual and automated testing before pushing to production.
All along, we maintained detailed documentation of our progress and collaborated closely using our internal team tools to ensure smooth communication and transparency. In hindsight, this phased and well-documented approach was one of the key reasons why our migration went smoothly.
Step 1: Easy Win with Sliders
Our slider component was the simplest, isolated, and safest starting point. We converted this component smoothly using Alpine.
Step 2: Forms - The Critical Challenge
Forms were our biggest concern. They generated leads essential to our business. We couldn't afford mistakes, so thorough testing and fallback mechanisms were mandatory.
Step 3: Simplifying Navbar
Previously, our navbar was overly complex, mixing vanilla JavaScript, jQuery, and Vue 2. We entirely rebuilt it using Alpine, drastically reducing complexity.
Results and Improvements
The results after switching to Alpine.js were immediate and impressive. Not only did we successfully modernize our front-end architecture, but we also achieved measurable technical and business outcomes:
JavaScript bundle size: Reduced by more than 50KB, resulting in faster load times.
Performance improvements: Lighthouse scores improved dramatically, jumping from 75 to 97.
Developer experience: We reorganized our large monolithic JavaScript file for forms into three distinct files: constants, reusable functions, and form logic. This made the codebase more modular, readable, and maintainable.
Selective JS loading: By embedding Alpine logic directly into the page HTML, we were able to ensure that JavaScript only loaded on pages where it was required. This drastically reduced unnecessary script loading and improved the experience for users on pages without interactive forms.
Improved team collaboration: This migration also encouraged stronger communication and documentation practices within our team, which will benefit us in future projects.
ref:- https://pagespeed.web.dev/analysis/https-www-fylehq-com-pricing/1wfb042zjn?form_factor=desktop
Challenges and Lessons Learned
One of the biggest differences we noticed between Vue and Alpine was around deep reactivity. In Vue 2, when data inside nested objects changes (for example,
user.profile.name
), Vue automatically updates the DOM. Alpine, on the other hand, only tracks changes at the top level ofx-data
objects. It does not automatically watch nested objects for changes. This limitation made complex form state tracking more challenging in Alpine and required us to structure our data and validation logic more carefully. While Alpine’s shallow reactivity helps keep it lightweight and fast, it does demand a different approach when working with deeply structured data.Our initial plan to migrate forms one by one had to be abandoned. A deeper analysis of the codebase revealed that all form logic was tightly centralized in a single file, forcing us to migrate every form at once.
Forms needed extensive testing to avoid business disruptions.
Navbar's transition required thoughtful planning and refactoring.
Tips for Your Alpine.js Migration
Here's a quick checklist to ensure a smooth migration:
✅ Audit thoroughly: Identify all Vue-dependent components clearly.
✅ Start small: Migrate simple, isolated components first to gain confidence.
✅ Prepare validators: Create or identify reusable custom validation methods.
✅ Extensive testing: Set up end-to-end tests for critical elements like forms to avoid disruptions.
✅ Fallback strategy: Always have rollback plans ready for high-impact migrations.
✅ Train your team: Ensure your development team is comfortable with Alpine's syntax and concepts beforehand.
Conclusion
Transitioning to Alpine.js was a significant yet rewarding endeavor. The website now loads faster, developers find it easier to maintain, and our business didn't experience any disruptions. If your static website needs a lightweight, powerful way to manage interactions, Alpine.js could be your ideal solution.
If you're considering lightening your website with Alpine.js, I highly recommend it. It's been a game-changer for us. Have questions or want to share your own migration story? I'd love to hear from you!