Vue vs React
Frontend Project from start to finish
Hi, Nick Barth here, I’m an experienced freelance fullstack developer, currently on contract for Braingineers. In the past I have created and maintained both Vue and React production apps, but on this project, I had the opportunity to build two apps simultaneously. I thought this would be a fun opportunity to compare two of the most popular frameworks from a developers perspective.
While having both React and Vue work side-by-side invites comparison, these frameworks do not have to be binary. Within a project, both frameworks can co-exist, and with careful evaluation of pros and cons, you may be able to use both next to eachother in your next project.
Internal Tooling? Don’t care about style? Big Old CRUD? React.
I decided on using React for the internal tooling, as the ecosystem was more mature, and we would be leaning heavily on libraries, specifically material-ui. With no designs, and no real requirements other than standard CRUD operations, I made the decision to leave nothing in question, and allow myself to be steered by the tenants of material design.
The introduction of hooks excited me for this, as there would be a large number of forms, and with hooks I’d be able to share common functionality between the forms. Context makes for an easy out of the box state management solution. Both of these new features were major selling points for this use-case of React.
Handrolled? Client-facing? Pixel Perfect? Vue.
Vue was chosen for the client-facing app; as I handrolled all of our UI primitives, I wanted flexibility and precision. We were blessed with a beautiful design, courtesy of Sander Crombach, and in short, we wanted this to look fantastic.
While, styling can be pixel perfect on both Vue and React, I found Vue’s native systems way more enjoyable to work with. The fact that we were writing all of our UI meant we could safely ignore the large ecosystem of prebuilt component libraries React has. This meant I had to be careful to build an iterable and maintainable codebase, which Vue’s opinionated approach was better suited for.
Below we are going to compare some aspects of our two projects.
The secret to getting ahead is getting started. Setup now!
As we did not need SEO, or have any performance concerns, I was unable to find compelling arguments for the use of Nuxt.js or Next.js. I stuck with the classics for both: Create-React-App and Vue CLI. Both are feature-rich, standalone tooling for their respective frameworks. Both offer easy and optional prepackaged configurations that cut down the time of setting up a project to almost nothing. Both CLI solutions offered excellent starter kits and documentation for me to get started, and as the project never got complex enough, I never had to eject Create-React-App.
I used Netlify to deploy the development versions of both applications, both of which integrated seamlessly with the SaaS provider. Both projects were up and running in their dev environments in ~10 minutes.
How to handle project directory
In my src folder, I had several more folders than we would have in React due to Vue’s opinionated approach to utility functions, which are split into directives and filters. I did not end up needing more than five of either. Routes contained the views, with fetching logic for the required data. Components was by far my biggest folder with 54 subfolders, as I wrote my own component library. We used Storybook to manage all of these components.
Our React app had a significantly smaller folder footprint, as we could jam everything into utils and hooks, so the only thing that was left was our routing and components. The component folder was rather limited in size as well, as we were using such an all-encompassing library in material-ui.
Making designers & developers happy with styling systems
In my components, I went with my favorite CSS stack.
While it is easy enough to scope CSS in Vue, I maintained discipline on BEM as I find it to be the best developer experience when trying to debug CSS issues.
However, in my routes, I decided to use Vue’s Single File Components (SFC). Because my routes had limited and repeatable styling, I gave these single files a shot, and, to my joy, it worked excellently! My worry was a large file length, however, a flex-box or a css grid was the largest bit of css I ended up writing in these files.
By keeping components small, we reduced most of the headache of writing BEM, and what’s leftover is cleaned up with SASS’s amazing should-be-native-css-trick nesting!
Material-ui’s current (there’s been some flipflopping) packaged styling solution is a CSS-in-JS solution. Like most frontends, I write most of my CSS in the browser, and the syntax change is frustrating to copy-paste with, it may seem like an arbitrary issue, but it greatly reduced my enjoyment of styling.
Their solution was rather lackluster, as I had no reason to enjoy the benefits of CSS-in-JS’s major advantages, theme nesting, dynamic styles, and self-support. In the end, it was what I feared - larger file lengths, camel-cased syntax, and lots of hooks to pass CSS around.
While it was easy enough to implement another system, I wanted to give their styling a fair chance. However, I do not think I would enjoy using CSS-in-JS again without an extremely proper use-case.
Routing and State Management, aka, keeping it scoped
The Vue app was behind an auth screen, so the first order of business was setting up the Vuex and VueRouter. I am trying to keep my global state as light as possible, so I only ended up keeping auth and another commonly used bit of user information in the store. VueRouter was extensively used and very much loved - its documentation was flawless, its Navigation Guards simple and supremely useful. VueRouter’s clear nested-array based routing is cleaner and miles ahead of the declarative approach seen in ReactRouter.
All routes were declared and managed from a single file in the root of my routes file. This centralization makes routing clear and readable for any people coming on to my project.
ReactRouter, now in version 5.x, has been an amorphous entity for the past 5 years of my developer experience. The current documentation is written in not ideal code-sandbox, however, I think the real weakness lies in its declarative nature.
React has implemented several native attempts to rid itself of the need for huge Redux libraries, React nailed it with React Context. It was a breeze, the React team has done an excellent job in implementing their own native alternative to global state management.
Developer Experience or: How I learned to stop worrying and love the Framework
Vue’s opinionated way of implementing SPA really improved my experience in building this app. I always knew where every file, route, line of CSS, filter, directive, and method was coming from. It’s very easy to structure your app in a maintainable fashion because of this enforced format. I found the only place I needed to maintain rigid discipline in was writing BEM CSS.
Every other architectural decision was taken care of for me, by Vue itself. This is a commendable way of building apps, as it will result in a standardized approach globally. This standardization of both documentation and implementation greatly contributed to my productivity and enjoyment while working on my Vue app.
Truly the wild west, anything can be done any way, with anything. React’s tiny API leads to a very diverse landscape of implementations. As I was using a prefab’d component library, I allowed the library to make as many decisions for me as possible, which cut the choice burden down by a bit.
Sharing logic between components was a breeze with the new hooks. Auth was handled charmingly with context. These well maintained and documented libraries contributed drastically to my production and speed while developing in React.
It takes a village to raise an app, the npm ecosystem
As I was hand rolling the majority of my components, I was not bothered with Vue’s relatively small and young ecosystem. It turned out to be okay. I tried to limit the number of external packages I used; in the end I required 17 packages. While all of them ended up working, the average stars and frequency of commits on these third-party libraries was much lower than their React counterparts. From charting libraries with no commits in months, to a select box with 120 open issues, in Vue, choosing open source libraries is a far less streamlined process than the popularity driven choices of React.
Documentation on all of the libraries was uniform in how fabulous they are. Thanks to VuePress, most of the documentation is standardized and efficient. This was a pleasant surprise, for I have never seen this in another ecosystem.
Overall, the Vue ecosystem was a better experience than I expected.
React has a stunning number of powerful open source libraries for the choosing! I mainly chose React for the ease and convenience of having Material-ui. I ended up using 20 packages for my React project. The documentation ranged from great (material-ui) to downright wretched (react-router).
Once again, React’s fragmented nature leads to difficulty maintaining good documentation, requiring separate documentation for hooks, and class components. Even stackoverflow questions have devolved into multiple answers due to the fluctuation in react versioning.
The evolution of React, while vastly improving the developer experience inside their IDE, has dramatically reduced the quality of the documentation and the libraries themselves, which are now forced to support both hooks and class components, or fall behind.
Although the overhead was great, React is moving in the right direction, and I applaud the boldness of their new direction.
Stuff I am curious about. But was too cowardly to try.
Due to the limited scope of this project, I left out a few processes and technologies in the name of shippin’ it. TypeScript, I have used in previous React projects and aside from a bit of a learning curve, greatly enjoyed using its features. However, I worry that with Vue’s weaker ecosystem, definitions would not be as readily available, I’d love for someone to let me know their results of using TypeScript and Vue.
Testing, is another angle at which I was unable to compare the frameworks, because I performed no testing throughout my development process. Both Create-React-App and Vue CLI have built in testing harnesses that I would’ve loved to have the chance to experiment with. Please let me know your opinions!
I’m curious about the Server-Side rendering capabilities of Vue. As I have used both Next.js and Razzle.js, and rolled my own Universal App, I understand and respect the difficulties of maintaining SSR in the React environment, and I am very curious to see how Nuxt.js handles one of the more unfriendly technologies a frontend encounters.
In the battle of React vs Vue, who cares! These frameworks are capable of co-existing, conceptually they are nearly identical, implementation and syntax making up the majority of the differences between them. A recap of the advantages of each:
- Opinionated (therefor standardized) implementation
- Uniform documentation
- Native transition support
- Mature and robust open source community
- Growth of native library, ie, hooks & context
- Transferable skills, gatsby.js
It was my pleasure building and maintaining both applications. From the perspective of developer experience, I believe the level of handrolling was the driving factor. Building (and therefor knowing) all of my components created three separate impact points.
- Knowing the components inside and out. If something went wrong, I could usually estimate get a very close estimate of where and what failed. I knew what tools I had available always, without need for a consultation of documentation.
- Everything was exactly as I wanted it, for example CSS-in-JS simply comes down to preference, and I prefer a separation of concerns. When choosing such an extensive component library, such as Material-ui, you are forced to work within their system.
- The accountability of a handrolled product is all on yourself or your team. I had to make 4 issues and 1PR for separate libraries while working in my React project, slowing down my development speed, and relying on teams with no interest in helping me. Every issue I had in my Vue product, was solely on me.
Thanks for reading, thanks to the open source community for building this awesome tools. Feel free to offer any corrections or suggestions.