Moving to Vue.js
Part 1: An Introduction
Moving away from MVP
To get started here, let me just make one thing very clear: I am a huge proponent of MVPs when building any piece of software. If my previous days as a contract software engineer have taught me anything, it’s that you can’t put a number on the amount of time, energy, and money wasted by building out every amazing feature idea before you put a product in front of your users and start getting feedback.
That being said, it should be considered a badge of honor for any software company, team, or developer to build a product that one day has to move past MVP stage and start thinking harder about scalability, efficiency, app structure, etc. Things you most likely passed over as you built out your first version as quickly as you could.
At Ground Signal we’re finally at that stage with our newest product and have begun to take a step back, look at what we have, how we got here, and what improvements we can make. I’ve decided to take a front-end approach and see what we can do to make the user experience better with all of the amazing new technology readily available, some of which wasn’t an option (or as developed as they are now) at the time we started building out our MVP.
When we initially started our MVP we’d chosen Ruby on Rails to serve up our content, and Ractive.js as our front-end framework. Without getting too far into the weeds, we chose Rails because we already had a ton of in-house experience there. I’m sure there were other options at the time, but this one made the most sense.
Why we chose to switch front-end frameworks
But alas, as I mentioned before, we are at a tipping point with Ractive.js and our code is starting to show it. We have components nested in other components, no real state-management (unless you consider storing everything on the root object state management…), if-else statements for days, and far more parent-child inheritance than we’d like. Given the way front-end frameworks have been seemingly moving at the speed of light over the past few years, we decided to take a look at what else is out there to help us tackle our main problem - page load time.
One thing that’s nice about Ractive.js is that it compiles everything ahead of time, and puts that in the DOM so it’s there for you when you need it. Unfortunately, that also leads to the problem of the browser having time parsing all that, even if some are unused. There has been some chatter over the years about adding lazy-loaded component templates, but it’s not built-in and it doesn’t seem to be a problem that will be solved any time soon. This is a huge problem for us as our app takes multiple seconds just to parse the loaded Ractive.js templates on the page on first load. While seconds doesn’t sound that crazy, watching the page creep into existence for multiple seconds at a time where we measure patience levels in single digit milliseconds feels like a lifetime (trust me, I live and drive in Boston).
While solving that problem we were hoping to also tackle a few issues that have come up over time:
- State Management — Ractive.js doesn’t have a single adapted state management system, so we’ve been forced to rely on storing everything on a single parent object and using that in all child components. As you can imagine, this gets messy over time (and you better not ever need to change that parent…). We’d love to move to a more uniform State Management system that will grow with our application in a cleaner, more concise manner, and separate concerns away from the actual application logic.
- Folder Structure — While we don’t need (or necessarily even want) a system that completely binds you to a certain folder structure, it would be nice to have a uniform setup that most apps have to help with new-recruit on-boarding, ease of navigation, etc.
- Webpack — When we originally started with Ractive.js we didn’t have some of the amazing functionality that Webpack has recently introduced like tree shaking, hot module replacement, and so much more. We’d love to see if that’s something we can take advantage of and move towards to help remove any unused code from making it into our production environment.
- Community — Over time as Ractive.js has been losing market-share to some of the bigger guys, the community is slowly moving away from it, which makes troubleshooting and support a bit more complicated
We knew right off the bat we had the following constraints that played a major roll in our development:
- We would need to move over existing JS, Pug, and SCSS code — ideally as plug-and-play as possible
- We need to utilize our existing in-house knowledge — we’d used in some capacity Ractive.js, React.js, Vue.js, and custom built jQuery-based systems
- We would need to do it in pieces. Unfortunately, with a small team and so much in the pipeline, we don’t have the time or bandwidth to do a full-code rewrite and launch a brand new product. We would need to start launching it piece by piece, without getting stuck in the land-of-two-frameworks where software projects become unusable as you fight conventions of two different frameworks side-by-side (not to mention trying to use data from one framework inside another, ugh).
- Our new framework had to have a large community built around it. We need to make sure that there are people out there that we can learn from, are willing to give us feedback, and that we can help out as we overcome our own struggles (which… lets be honest… we will have).
What were our options
- Redux top-notch state management
- Doesn’t preload all of the templates
- Flexible and works with all major libraries out of the box
- Amazing community of knowledgable, experienced developers (just google `react.js` to see what I mean)
- Tons of behind the scenes optimization built-up over time
- Great developer tools
- React.js, while being a great product for a large-scale application over-time, is tough to master immediately and write clean, concise code (when compared with other frameworks we looked at)
- Large (>144KB with add-ons for state management and routing)
- Built using third-party components, not maintained by the React.js development team (example, react-router used for routing)
Vue.js is often thought of as a combination of some of the best parts of Angular and React.js. Since it was released much later than React.js (not coming onto the scene until 2014), it’s had plenty of time to learn from its predecessors, and has done a great job of merging their top features like Angular’s two-way binding and a React.js-like virtual dom. It’s also used by some of the big guns (Expedia, Alibaba, Nintendo, etc.) so it, too, comes with a certain level of confidence out of the box.
- Vuex state management deeply integrated
- Built in vue-router (versus our own custom page.js implementation)
- Awesome dev-tools functionality with live-reloading
- Doesn’t preload all of the templates
- It uses different sections of each component for JS, CSS, and templates so it seems more straight forward to transition from our existing Ractive.js files.
- Can easily be modified to accept various templating languages (Pug, in our case)
- Extremely small (~30KB gzipped with vue-router and Vuex included)!
- Single .vue file for each component. Not entirely a con, but more something to get used to. Files are setup with view, styles, and the JS in a single .vue file. This is kind of nice actually, as everything you’d change for a single page is in one file… but just different. Note: We’ve learned you can actually separate out the JS/styles/template into their own files and reference them via src tags)
- While it’s obviously growing in reputation, it’s hard to overlook the fact that it’s much newer than React.js… and isn’t built by Facebook
The Final Decision
If you remember above, our biggest complaint about our existing Ractive.js app was the time it took to load our app on initial load. As it is, both React.js and Vue.js would solve that problem so we had to base our decision on all of the other fun stuff.
We set out to figure out which one would be the fastest to implement, cause the least amount of pain to our small team of front-end engineers, and grow with us as we continued to implement all of our great new features for 2018. We spent a few days building out simple React.js and Vue.js apps that hooked into our existing API for login, used Pug files for templates, and SCSS for our styles. It didn’t take us that long to realize that Vue.js was the right choice for us:
- We wouldn’t have to completely rewrite our existing code into correctly formatted JSX code! Yay!
- It allowed us to take advantage of our existing JS and SCSS linting (so our code format remained consistent) by splitting our files up into separate .js, .scss and .pug files if we chose too (not sure how we feel about a single long file as of now… but we’ll see)
- It took hours (not days) to have a fully functional sample app that we all understood by everyone. The code format of Ractive.js vs. Vue.js is extremely similar (base files with data, computed variables, methods, and lifecycle events)
- Vuex state management and Vue-Router were so easy to implement that I was done before I thought I’d actually started
This isn’t to say that React.js isn’t also an amazing library and if you’re seriously considering starting an app from scratch, check it out! It has so many nice features (just check out the Advanced Features section) that you should consider when going through your own selection process. If you have more time than we had, you might also want to give Angular a look, I hear good things :)
Vue.js won over for us because we needed to find the best possible solution to reduce our transition time and development effort while still taking advantage of all the new technology and advances being made in the front-end world. It was a solid balance between the overwhelming amount of features of React.js and the structure we’re used to from our existing Ractive.js components, while constantly being ranked one of the fastest front-end libraries around.
I’m going to stop there for today, but feel free to shoot over any messages, feedback, or thoughts that could help us (or anyone else) as they try to tackle the transition from MVP to whatever comes next. We wanted to turn this into a series because let’s be completely honest here, there are very few teams out there that have time to spend months or longer rebuilding their front-end app every time new technology comes out and you’re missing out on some awesome features. That, and selfishly, we love all the feedback so we can constantly be making our own app better :)
Here’s some of the stuff we have planned in this series:
- Setting up our initial Vue.js app (and some snags we ran into with SCSS mixins and shared files)
- How we transitioned slowly by building our own custom Vuex-like state management in Ractive.js
- Turning on Ractive isolated mode to pinpoint some problem areas by breaking everything
And plenty more, stay tuned!