DEV Community

Daniel Elkington
Daniel Elkington

Posted on • Updated on

Vue's Darkest Day

Today I was amazed to see the usually positive and friendly VueJS community descend into a bitter war. Two weeks ago Vue creator Evan You released a Request for Comment (RFC) for a new function-based way of writing Vue components in the upcoming Vue 3.0. Today a critical Reddit thread followed by similarly critical comments in a Hacker News thread caused a flood of developers to flock to the original RFC to voice their outrage, some of which were borderline abusive. It was claimed in various places that

  • All Vue code would have to be rewritten in a totally new way because the existing syntax was being removed and replaced with something else;
  • All the time people had spent learning Vue had been wasted given everything was about to change;
  • The new syntax was worse than the old, did not enforce structure, and would lead to spaghetti code;
  • The Vue Core team had suddenly implemented a huge breaking change without any consultation;
  • Vue is turning into React!
  • No, Vue is turning into AngularJS/Angular!
  • All HTML now needs to be written as a giant string!

With walls of negative comments on the Reddit Thread one may be surprised to discover on going to the RFC page that You's RFC has an overwhelmingly high ratio of positive to negative emoji reactions, and many of the initial comments were quite positive. Indeed, the very first comment is particularly full of praise.

I was the person who wrote that first comment. I happened to get a notification that there was a new RFC, read it straight away, saw that it was just what I wanted from Vue 3.0 and that it would help immensely, and left the first comment within 15 minutes of the RFC being published to express my gratitude. I hope to expand here on why I think the new proposal is such a great idea, but first, to address some of the criticism.

I suspect that many people got a little worked up after reading the Hacker News or Reddit threads which had some somewhat misleading comments, and voiced their outrage without reading the original proposal. Evan You has now updated the proposal with a Q&A that addresses many of the issues people have, but to summarise,

  • You don't need to rewrite any code if you don't want to - the new syntax is additive, and the old syntax will remain valid throughout Vue 3.0 and as long as it is still widely used. Even if it eventually gets removed from the Core code, plugins could easily allow the old syntax to be still 100% valid.
  • Time spent learning Vue was not wasted - the new component syntax uses the same concepts that you spent time learning, and other concepts such as Single File Components, templates, and scoped styles work exactly the same.
  • A change hasn't been made without consultation - the RFC is the consultation. The new syntax is still a long way from being released.
  • And no, HTML code doesn't need to be written as a giant string.

A slightly more subjective point is that the new syntax is inferior to the old, and will lead to less structured code. I hope to demonstrate with a simple example why I got so excited when I saw the RFC, and why I think it is superior and will lead to better structured code.

Consider the following fun component that allows a user to enter details of their pet. Note that

  • A message gets displayed when they finish typing their pet's name;
  • Another message gets displayed after they select their pet's size. Form before any data entered - messages are not displayed Form after data entered - messages are displayed

You can try out a demo of the component here and can view the full code using Vue 2.x here (see components/Vue2.vue).

Consider the JavaScript of this component:

export default {
  data() {
    return {
      petName: "",
      petNameTouched: false,
      petSize: "",
      petSizeTouched: false
    };
  },
  computed: {
    petNameComment: function() {
      if (this.petNameTouched) {
        return "Hello " + this.petName;
      }
      return null;
    },
    petSizeComment: function() {
      if (this.petSizeTouched) {
        switch (this.petSize) {
          case "Small":
            return "I can barely see your pet!";
          case "Medium":
            return "Your pet is pretty average.";
          case "Large":
            return "Wow, your pet is huge!";
          default:
            return null;
        }
      }
      return null;
    }
  },
  methods: {
    onPetNameBlur: function() {
      this.petNameTouched = true;
    },
    onPetSizeChange: function() {
      this.petSizeTouched = true;
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

Essentially we have some data, properties computed off that data, and methods that manipulate that data. And notice that in Vue 2.x there is no way to keep related things together. We can't keep the petName data declaration next to the petNameComment computed property or the onPetNameBlur method because in Vue 2.x things are grouped by type.

Of course this doesn't matter too much for a small example like this. But imagine a bigger example, that had multiple pieces of functionality that needed data, computed, methods, and even a watcher or two. There's currently no good way to keep related things together! One might use something like Mixins or Higher Order Components but these have issues - it's hard to see where properties are coming from and there are problems with namespace clashing. (And yes, in this case it would be possible to split things into multiple components, but consider this similar example where it isn't.)

Rather than organising components by option type, the new proposal allows us to organise components by actual functionality. It's similar to how you organise your personal files on your computer - you usually don't have a 'spreadsheets' folder and a 'word documents' folder, instead you might have a 'work' folder and a 'holiday plans' folder. Consider the above component written in the proposed syntax (as best as I am able to without seeing the output - let me know of any bugs you see!):

import { state, computed } from "vue";
export default {
  setup() {
    // Pet name
    const petNameState = state({ name: "", touched: false });
    const petNameComment = computed(() => {
      if (petNameState.touched) {
        return "Hello " + petNameState.name;
      }
      return null;
    });
    const onPetNameBlur = () => {
      petNameState.touched = true;
    };

    // Pet size
    const petSizeState = state({ size: "", touched: false });
    const petSizeComment = computed(() => {
      if (petSizeState.touched) {
        switch (this.petSize) {
          case "Small":
            return "I can barely see your pet!";
          case "Medium":
            return "Your pet is pretty average.";
          case "Large":
            return "Wow, your pet is huge!";
          default:
            return null;
        }
      }
      return null;
    });
    const onPetSizeChange = () => {
      petSizeState.touched = true;
    };

    // All properties we can bind to in our template
    return {
      petName: petNameState.name,
      petNameComment,
      onPetNameBlur,
      petSize: petSizeState.size,
      petSizeComment,
      onPetSizeChange
    };
  }
};
Enter fullscreen mode Exit fullscreen mode

Note that

  • It's ridiculously easy to group related things together;
  • By looking at what gets returned by the setup function we can easily see what we have access to in our template;
  • We can even avoid exposing internal state ('touched') that the template doesn't need access to.

On top of that, the new syntax easily allows full TypeScript support which was difficult to achieve in the Vue 2.x object-based syntax. And we can easily extract out reusable logic into reusable functions. Something like

import { state, computed } from "vue";

function usePetName() {
  const petNameState = state({ name: "", touched: false });
  const petNameComment = computed(() => {
    if (petNameState.touched) {
      return "Hello " + petNameState.name;
    }
    return null;
  });
  const onPetNameBlur = () => {
    petNameState.touched = true;
  };
  return {
    petName: petNameState.name,
    petNameComment,
    onPetNameBlur
  };
}

function usePetSize() {
  const petSizeState = state({ size: "", touched: false });
  const petSizeComment = computed(() => {
    if (petSizeState.touched) {
      switch (this.petSize) {
        case "Small":
          return "I can barely see your pet!";
        case "Medium":
          return "Your pet is pretty average.";
        case "Large":
          return "Wow, your pet is huge!";
        default:
          return null;
      }
    }
    return null;
  });
  const onPetSizeChange = () => {
    petSizeState.touched = true;
  };
  return {
    petSize: petSizeState.size,
    petSizeComment,
    onPetSizeChange
  };
}

export default {
  setup() {
    const { petName, petNameComment, onPetNameBlur } = usePetName();
    const { petSize, petSizeComment, onPetSizeChange } = usePetSize();
    return {
      petName,
      petNameComment,
      onPetNameBlur,
      petSize,
      petSizeComment,
      onPetSizeChange
    };
  }
};
Enter fullscreen mode Exit fullscreen mode

In Vue 2.x I often find myself writing a "monster component" that is hard to break up into smaller pieces - it can't be decomposed into other components because there is too much happening based on a small amount of state. However using the proposed syntax it's easy to see how big components could have logic broken up into smaller reusable pieces, moved into separate files if necessary, leaving you with small, easy-to-understand functions and components.

Is this Vue's darkest day so far? It looks like it. What was until now a community mostly united behind the project's direction has splintered. But I have hope that people will take another look at a proposal that doesn't break anything, still allows them to group things by option type if that's what they like doing, but allows for so much more - clearer code, cleaner code, more interesting library possibilities, and full TypeScript support.

Finally, when using open source software, it's good to remember that the maintainers are putting a lot of effort into something that you get to use for free. Some of the borderline abusive criticism seen today is something that they really shouldn't have to put up with. Thankfully the disrespectful comments were a minority (albeit a sizeable one) and many were able to express themselves in a more respectful manner.

Update June 23 2019:
I wrote the original post very quickly and without expecting it to receive the attention that it has. Since then I've realised that the code example was too complex for the point I was trying to illustrate, so I've simplified it greatly. The original code sample can be found here.

Latest comments (112)

Collapse
 
ozzythegiant profile image
Oziel Perez • Edited

Let me tell you something. I hated the whole React hooks system. It has been an absolute mess of a pattern because developers, no matter how much we teach them to separate concerns and to keep things maintainable, continue to create large, bloated, and messy components. Additionally, we keep treating functions like classes. Classes have properties and methods, functions don't, yet we have this hooks antipattern infecting not just React, but now Vue; it's just not natural. You get much better legibility with classes and objects because I can quickly look for where props, methods and data are supposed to be. Now I have to look for an endless list of const variables that are intermingled and not separated carefully. You can say that this API is optional, but look what happened to React, their hooks are optional too but the whole industry decided to use them for everything, so who's to say that might not happen with Vue too. I'm sorry but I'm not supporting this Composition API, but sticking to Vue-Property-Decorator as soon as it finishes migrating. If I'm gonna be forced to write this way in the future, I might as well move to Svelte instead. If I want better performance, Svelte is beating all three major frameworks already.

Collapse
 
yashsway profile image
Yash Kadaru

Thank you for this post! "Finally, when using open source software, it's good to remember that the maintainers are putting a lot of effort into something that you get to use for free." - This 100%. As a software engineer, I'm thankful everyday to the thousands of people pouring their heart into open-source. It is mind boggling how one can be so small-minded and rude.

Collapse
 
leob profile image
leob • Edited

Great explanation of the advantages of the new syntax! If used well this can greatly improve modularity and reuse, but it requires some getting used to this new way of thinking.

But I think any ambitious and open-minded Vue dev/user welcomes this.

Collapse
 
rogerjohn0 profile image
Roger John

This is what happens when the core values are not adhered to. And Typescript now? Really? Typescript is not JavaScript.

Collapse
 
egranville profile image
Edward

The main reason I see this as the darkest day for Vue. Is that they are actively choosing to abandon the one thing that made Vue so popular and morphing it into something that starts to look like react. With that you loose your right to exist. More developers would have chosen react over Vue if it wasn't for Vue's current style.

What they should have done? Keep the good and loved bits and make the bad ones better:

  • Vuex is not what it needs to be
  • We need to share functions between components like we do with filters
Collapse
 
angularnodejs profile image
AngularNodeJS πŸš€ • Edited

This already happened with Angular with many breaking changes and along the way many people left and I'm guessing learned to hate Angular.

I am just starting off ramping-up on Vue + TypeScript for a new consulting role. For me, as long as the TypeScript code remains the same I don't care what the underlying JS code looks like.

I personally think Vue.js is still to basic and not a mature Framework or productive as Angular. It will continue to evolve and break things along the way. It will come up with new way to do things.

I'm guessing a lot of junior coders scared of by Typescript and Angular see Vue as simple and easy to learn. So if their reality of "simple" is threatened, they will get upset. If they are forced to do things in new way, they will get upset.

You didn't address the fact that new hipster coders will always want to use the new way to do things, but you will still have a lot of coders who want to do it the old way. No one likes changes and having to keep learning. Most developers want ROI on their learning.

As a consultant, I hate breaking changes, because then I am forced to work on legacy code and also forced to learn the new way because hipster coder like to change stuff up. This is just a problem with the JavaScript eco-system and JS coders in general. JS is like building a house on sand. In a few weeks to a month, code that once worked will break.

Collapse
 
navicsteinr profile image
Navicstein Rotciv

Well, if you ask me, I'll say that nothing lasts forever 😁, Vue is subject to change and So is every other thing 🀷

Collapse
 
jeck5895 profile image
jeck labasan

agree vue is becoming more like react

Collapse
 
jnnrz profile image
Johann

What a mess. It looks like React and that's not a good thing.

Collapse
 
danielelkington profile image
Daniel Elkington

If you get a chance, I'd recommend taking a look at this live coding presentation of the Composition API in action. I think it helps to demonstrate how much cleaner things can be with this new syntax - much better than the example in my post! youtube.com/watch?v=JON6X6Wmteo

Collapse
 
jdmerinor profile image
Juan Merino

Something about this new API reminds me quite a lot to Knockout JS. What you are exporting is basically the viewModel that we have in KO and you can also declare the computed properties, normal properties, etc in quite a similar way that the old dog KO :P I'm not sure if I'm the only one seeing the similarities here hehe

Collapse
 
wenish profile image
Wenish • Edited

Well the new style just looks like react.
And what i dont like about this style. You dont know where stuff is.
Everyone structers the functions else. Every group can be split diffrently.
Already those simple examples are hard to read.

In the current syntax i know exactly where to look at.

I use vue because i like vue not because i want it to be like react or angular

Btw. simple example but already big diffrents between lines count.

Collapse
 
smilingkite profile image
Katinka Hesselink

I started using Vue after having worked on personal projects with react. So I was very much a beginner. I LOVED the fact that I did not have to differentiate between different syntaxes, as I did with React.

So yes - from a beginner's perspective, this change WILL make things harder. I can't say I understand the new syntax yet.
The current one is super-intuitive for front-enders. If you know HTML, CSS and Javascript, the template structure is an obvious way to organise things. Sure, for advanced use it has limitations, but it is so VERY legible. I love it.

I suspect that I would hesitate to use the new syntax as a default, simply because the old one is so much more intuitive.

In the example code I'm totally lost: where is the html that gets rendered? I don't even see a render function! (as I would have in react).

Collapse
 
joelvarty profile image
Joel Varty

Nice article. Vue code is starting to look my old-school knockout code a little.

I haven’t started using TypeScript with Vue, but I will definitely look at this new structure when I move to that.

Thanks!

Collapse
 
emmymay profile image
EmmyMay

Your second example already has more code. More code scares me and I'm sure there are people like me who gets put off by more code. In the case of apps with multi functionality. Does Vuex not solve that problem?

Collapse
 
perpetual_education profile image
perpetual . education

Sounds like a fun time to learn Ember.js!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.