Dark day for Vue.js

Original author: Daniel Elkington
  • Transfer

Today I was amazed at how the usually positive and friendly Vue.js community slipped into a sad confrontation. Two weeks ago, Vue creator Ewan Yu published a proposal (RFC) with a new feature API for components in the upcoming Vue 3.0. Today, a critical discussion on Reddit and similar comments on Hacker News have caused an influx of developers into the original RFC with outrage, sometimes even too harsh.


It stated something like the following:


  • All Vue code will have to be rewritten in a completely new way, because the existing syntax will be removed
  • All the time that people spent studying Vue turned out to be in vain, because everything will change
  • The new syntax turned out to be worse than the old, does not give a clear structure and generates spaghetti code
  • Vue team rolled out a big change without consulting anyone
  • Vue turns into React!
  • Or not, in AngularJS / Angular!
  • All HTML will now have to be written in one huge line!

After the wall of negative comments on Reddit, it is surprising that the discussion of the RFC itself contains a mostly positive reaction, especially among the first comments. In fact, the very first comment is full of enthusiasm.


I was the person who wrote this first comment. It turned out that I received a notification about the new RFC, immediately read it and found that this is exactly what I would like from Vue 3.0 and wrote a comment about it within 15 minutes after the publication of the RFC to express my gratitude. In this post, I hope to reveal this topic, why I consider the new API to be such a good idea. But first, let me answer the critics' statements.


I suspect that many people became embarrassed after reading Hacker News or Reddit, where there were many unreliable comments that were misleading, but did not read the original sentence . Evan has already added a Q & A section that answers most of the questions:


  • You don’t need to rewrite anything from scratch if you don’t want to - the new syntax is a complement, while the old one will remain with us throughout Vue 3.0 until it is actively used. Even if it is eventually removed from the main code, it can be easily returned using plugins .
  • Time for learning Vue was not wasted - the new syntax works the same way as before, with familiar concepts such as single-file components, templates, and local styles.
  • The change was not made without discussion - this RFC is the discussion. The new syntax is still far from the final release.
  • And no, HTML doesn't have to be written like a huge string

There was a somewhat subjective point about the fact that the new syntax generates less structured code. I want to demonstrate this with a simple example that will explain why I am so enthusiastic about the RFC and why I think that the new approach will lead to more structured code


Imagine a component that allows the user to enter information about their pet and is updated as you enter data. Wherein:


  • The title text is updated depending on the name of the pet.
  • The color of the stroke depends on the selected color of the animal, including the shadow, the color of which is calculated based on the selected color.
  • Header font size and stroke style depend on user-selected animal size


Component appearance


You can see the live demo with the component here and also see the source code for Vue 2.x here (file components / Vue2.vue).


Consider the Javascript part of this component:


  data() {
    return {
      petName: "",
      petColor: "#000",
      petSize: ""
    };
  },
  computed: {
    header: function() {
      if (this.petName) {
        return "My Pet " + this.petName;
      }
      return "Enter Pet Details";
    },
    petColorDarker: function() {
      return tinycolor(this.petColor)
        .darken()
        .toString();
    },
    shadow: function() {
      return "2px 2px " + this.petColorDarker;
    },
    borderStyle: function() {
      switch (this.petSize) {
        case "Small":
          return "dotted";
        case "Medium":
          return "dashed";
        default:
          return "solid";
      }
    },
    headerSize: function() {
      switch (this.petSize) {
        case "Small":
          return "12px";
        case "Large":
          return "60px";
        default:
          return "30px";
      }
    }
  }

Basically, we have some kind of data and various properties computed from this data. Note that in Vue 2.x there is no way to put related things together. We cannot place an ad petColornext to a computed one petColorDarker, because in Vue 2.x they are grouped by type.


Of course, for such a small example, this is not very important. But imagine a larger example, in which there are pieces of functionality with the necessary data, calculated properties, methods, and even with a couple of watchers. Now there is no good way to combine related entities together! Someone might think of mixins or higher-order components, but they have problems - it's hard to see where these properties come from, and there are also name conflict problems.


The new syntax offers the organization of components by related functionality, instead of the value type. This is similar to how you organize files on your computer - usually you do not create separate folders for excel tables and word documents, rather there will be folders like work or vacation planning. Let's imagine what our component will look like in the proposed new syntax (how much this will happen without the ability to run the code - let me know if you find any bugs):


  setup() {
    // Pet name
    const petName = value("");
    const header = computed(() => {
      if (petName.value) {
        return "My Pet " + petName.value;
      }
      return "Enter Pet Details";
    });
    // Pet color
    const petColor = value("#000");
    const petColorDarker = computed(() => {
      return tinycolor(petColor.value)
        .darken()
        .toString();
    });
    const shadow = computed(() => "2px 2px " + petColorDarker.value);
    // Pet size
    const petSize = value("");
    const borderStyle = computed(() => {
      switch (petSize.value) {
        case "Small":
          return "dotted";
        case "Medium":
          return "dashed";
        default:
          return "solid";
      }
    });
    const headerSize = computed(() => {
      switch (petSize.value) {
        case "Small":
          return "12px";
        case "Large":
          return "60px";
        default:
          return "30px";
      }
    });
    // All properties we can bind to in our template
    return {
      petName,
      header,
      petColor,
      shadow,
      petSize,
      borderStyle,
      headerSize
    };
  }

Notice, that:


  • It's amazingly simple to group related entities together.
  • Looking at the return value of the setup function, we immediately see what we have access to in the template.

In addition, the new syntax provides full Typescript support, which was difficult to achieve with Vue 2.x's object syntax. And we can refactor our logic by transferring it to reusable functions. Something like this:


function usePetName() {
  const petName = value("");
  const header = computed(() => {
    if (petName.value) {
      return "My Pet " + petName.value;
    }
    return "Enter Pet Details";
  });
  return {
    petName,
    header
  };
}
function usePetColor() {
  const petColor = value("#000");
  const petColorDarker = computed(() => {
    return tinycolor(petColor.value)
      .darken()
      .toString();
  });
  return {
    petColor,
    petColorDarker
  };
}
function petSizeToBorderStyle(sizeWrapper) {
  const borderStyle = computed(() => {
    switch (sizeWrapper.value) {
      case "Small":
        return "dotted";
      case "Medium":
        return "dashed";
      default:
        return "solid";
    }
  });
  return { borderStyle };
}
function petSizeToHeaderSize(petSizeWrapper) {
  const headerSize = computed(() => {
    switch (petSizeWrapper.value) {
      case "Small":
        return "12px";
      case "Large":
        return "60px";
      default:
        return "30px";
    }
  });
  return { headerSize };
}
export default {
  setup() {
    const { petName, header } = usePetName();
    const { petColor, petColorDarker } = usePetColor();
    const shadow = computed(() => "2px 2px " + petColorDarker.value);
    const petSize = value("");
    const { borderStyle } = petSizeToBorderStyle(petSize);
    const { headerSize } = petSizeToHeaderSize(petSize);
    return {
      petName,
      header,
      petColor,
      shadow,
      petSize,
      borderStyle,
      headerSize
    };
  }
};

In Vue 2.x, I often found that I am writing a “monstrous component” that is difficult to break into small pieces - it cannot be divided into smaller components, because too much is happening based on a small number of state variables. However, with the new syntax proposed, it can be seen that you can easily extract logic from large components into separate pieces, put it into separate files, if necessary, by obtaining small and easy-to-understand functions and components.


Did Vue have a darker day? Probably not. The former community around the project split. But I have a hope that people will look again at the RFC, which does not break anything, because it allows people to still group entities by type, if they like it, but also allows much more - more understandable and clean code, more options for libraries and full Typescript support.


And finally, when using open source, it would be nice to remember that its developers put a lot of effort into what you get for free. The overly harsh criticism we see today is not something that suits us. Fortunately, disrespectful comments were in the minority (albeit significant), and most were able to express themselves in a more appropriate tone.


Also popular now: