📜 ⬆️ ⬇️

How I started to love Vue

Introduction



This post is a logical continuation of my post / article - How I stopped loving Angular / How I stopped loving Angular .
It is recommended to read before reading.


For about a year now in all projects in which I participate, I use Vue instead of Angular.
In this post I will share the main impressions and differences after Angular, as well as tell some things from the actual experience of using Vue on combat projects.


Short recap of the previous post:


Here is a brief list of the main problems that bothered me in Angular at the time of writing the previous article:


  1. Horrible router
  2. Heavy and practical useless Dependency Injection (see below)
  3. Extremely controversial system of modules (not used in any other framework)
  4. Many superfluous and few useful abstractions, strange API-design
  5. Observable as part of the framework
    ...

DI


You should immediately make a reservation about Dependency Injection: after switching to Vue, it’s still worth noting that in Angular it’s more convenient to mock external dependencies in unit tests.


This depends entirely on the code base and internal best-practices, but often in Vue it is more difficult to mock something in tests than in Angular (the example will be lower).


However, I do not consider this to be a serious reason for the use of a pattern so alien to JavaScript on the front end.


Why not about the reactor


And one more small reservation regarding why Vue was chosen, and not React.
Disclaimer: all points below are VERY subjective (therefore, they should not be taken as criticism, but only as a personal view):


  1. Reactive in Vue just works, and immediately and asynchronously: there is no need to bother with immunity and clean functions
    (Immunity concept is very cool, but often extremely verbose - it is almost always long and expensive)
  2. JSX is bad for several reasons:
    • Slow migration of HTML markup to application code - especially designers who suffer here sometimes have to involve a developer for rather trivial things.
    • Constantly, even without special need, it is necessary to split everything into small components, which takes time VS standardization in Angular / Vue - components are removed as necessary at any moment
    • In my memory, memories of air condition = pain are still fresh
  3. Hellish forms - about it later
  4. reate-react-app in my opinion, today, is the least functional CLI of all the most popular frameworks, so for React it is worth creating a much more powerful tool for a long time
  5. Our team had quite a lot of experience with Angular - for a number of similar factors it was much easier for them to enter Vue

Differences and impressions after Angular


A little about the main differences and impressions that I noted for myself when switching to Vue.


Documentation


The first thing you come up with when choosing a UI framework is, of course, the documentation.


I will not re-parse the Angular documentation with its


Banana in a box

I can only say that in Vue it is much simpler and more intelligible.


I will not give examples, because all of them may seem subjective to you, while starting to read the docks, you immediately feel that they were written for people.


It is also worth noting that the docks are written in 6 languages, although English would be enough (I think that now any developer should know English at least at the reading level).


CLI


From my previous article, you could understand that I had previously thought that the Angular CLI is the best , but as it turned out:


  1. It is sometimes extremely difficult to customize.
  2. Angular and CLI is broken into many @angular and CLI packages with different versions, which, in turn, leads to a tremendous problem when upgrading the CLI / angular version.
    What is already done is not very simple


On the other hand, Vue CLI 3 is the coolest CLI for today.


  1. Customization is extremely convenient, any package can be added at any time, thanks to the plugin system
  2. Simplicity and flexibility through the use of a webpack


Zone.js vs Vue Reactivity


Angular uses Zone.js to track changes, which monkey patches for this standard API, like setTimeout .


This leads to certain problems:


  1. Difficulties with non-standard API , sometimes quite difficult solvable
  2. Horrible spectra
  3. Generally speaking IMHO, this is a hack, and far from being the most elegant

Vue does not need Zone.js, tracking works by turning all data / state into Observer.


At one time, when I saw sortsy, I was even somewhat upset that there was no magic.


At the top level, everything is trivial: Vue goes through all the objects through Object.defineProperty (for this reason, IE8 and below are not supported) and thus adds a getter and a setter.


Even nothing special to add ...


However, this approach has pitfalls, but they are extremely simple to describe and easy to understand.
And the understanding is not so much Vue, as the JS itself is at its core.


In Vue, you cannot dynamically add new root reactive properties to an existing instance. However, you can add a reactive property to nested objects using the Vue.set method (object, key, value):

 var vm = new Vue({ data: { a: 1 } }) //  vm.a —   vm.b = 2 // vm.b   Vue.set(vm.someObject, 'b', 2) 

It should also be noted that since version 2.6, Vue will not have these problems either, since there will be a transition to the Proxy, and it will be possible to also track the addition / removal of prop.


Rx and State Management


In Angular, from the box, the core of the framework was RxJS, everything is Observable.
Despite my love for Rx, many people and I had questions about whether it was needed inside Angular?


Especially at first, many people simply turned Observable into promises through .toPromise() .


And in general, the idea of ​​a shared data bus is not the easiest to understand, in addition to the complexity of Angular itself.


At the same time, being such a massive framework, Angular out of the box does not provide implementation of the most popular data management pattern for today - State Management.


There is NgRx , but it became fully usable not so long ago - as a result, we even have an old project with a custom implementation of a Redux-like stor.


And now about Vue.


Not only can any RxJS fan be able to easily connect it at any time by simply adding a new package.


Already there is even Vue-Rx , allowing the use of RxJS Observabl'y along with data.


If we talk about State Management, that is a great official Vuex.
At one time, with great surprise, I discovered that besides him there are also a huge number of alternatives .



Drop in


Actually, this is where the main advantage manifests itself (although it may seem like a disadvantage to someone) Vue - everything can be connected as needed.


Just add:


  1. Water
  2. Rxjs
  3. Vuex
  4. TypeScript
  5. SCSS
    ...

What would you lack, it always integrates simply and quickly.


Router


The reason for one of the most severe psychological injuries I received from Angular is a router.
Despite the fact that he has already corresponded three times, he is still terrible (yes, I repeat).


I will not describe all his problems in detail, but since the topic is sore, briefly:


  1. There are no named routes (!) - one of the strangest decisions that could be made is to remove named routes, thereby reducing the ease of supporting complex applications at times
  2. A strange system of events, which need to be checked by type,
  3. Transformation of the parameters of the route into Observable - sometimes it is extremely inconvenient to work with them if you need them only once at the start of the component
  4. Commands were created for navigation, a very strange and not very useful solution, no longer used in any router
  5. Lazy Loading via the string name of the modules, in the application entirely in TypeScript ... without comments
    … etc.

If you look at the sources, you can understand that many of these problems are related to the complexity and functionality of the router.


That is, do not even be in it strange solutions like teams, the number of features still makes it difficult and difficult.


In Vue, the router is extremely simple and working.


Speaking of simple, it should be mentioned that at one time I did not find the usual Angular parameter abstract: true .


Out of the box it is impossible to make a route without a template, but this is solved in one line of code - by creating a component like:


 // AbstractRoute.vue <template> <router-view/> </template> 

Is it bad that there is no such functionality out of the box?


And yes and no, because on the one hand it is important how easy the problem is solved, and on the other - the complexity and speed of the router itself (as opposed to tricky Angular).


By the way, here's the cool thing:


  path: `url/sub-url/:id', component: MyComponent, props: true 

Now the component MyComponent will have a props id , which will be a parameter from the URL.
This is an elegant solution, because id will immediately be reactive and it's very convenient to use it in the component (again, it just works ).


Expansion and Reuse


On the one hand, all components in Angular are TypeScript classes.
Despite this, the use of many TypeScript chips is often either inconvenient or impossible.


This applies primarily to OOP - inheritance, abstract classes, scopes.
The main problems arise with Dependency Injection and AOT compiler (God forbid you run into them ).


In Vue, the instance configuration is an object — it’s easy to work with and expand, refactor.
To reuse the code there are powerful things - Mixins and Plugines (see below for details).


UI components


In the Enterprise segment, components usually have a finished design, mock-ups, and so on. Most often, they are written from scratch, immediately sharpened for a specific task / product / project.
But not always developers have the opportunity to create everything from scratch, especially with pet projects and prototyping.


Here libraries ready UI components come to the rescue, and for Vue there is already a great many of them: Element, Vuetify, Quasar, Vue-Material, Muse, iView, and so on.



Especially I would point out Element and Vuetify, the impressions are strictly positive: beautiful and stable components for any needs, good docks.


We also like the set of Buefy components based on the cool Bulma CSS framework, it is especially convenient to use it in Bulma applications, where third-party components are connected as needed.


In the case of Angular - Enterprise-level component libraries of just a couple of pieces, this is primarily Angular Material (Google) and Clarity (VMWare).


Unfortunately, the rate of development of Clarity has recently declined, which is even more frustrating in terms of Angular's prospects in this matter.




Real experience and problems


And now the main problems from the real experience of using Vue in combat projects.


Too much freedom


The main problem Vue for serious projects, today, I would call too much freedom of choice.


On the one hand, the fact that the same thing can be done in many different ways is very cool.


But, in reality, this leads to the fact that the code base becomes rather inconsistent.


An exaggerated example: custom logic on a page can be made by declaring a certain component, and it can be as local


 const Component = { created() { // logic ... }} new Vue({ components: [Component], 

and global (accessible from everywhere).


 Vue.component('Global', { created() { // logic ... }}) 

You can make a local Mixin which will implement this functionality.


 const mixin = { created() { // logic ... }} new Vue({ mixins: [mixin], 

and it (admixture? is it? ..) again can be global.


 Vue.mixin({ created() {// logic ... }}) 

In the end, there are plugins that do almost the same thing as global mixins.


 const MyPlugin = { install(Vue, options) { Vue.mixin({ created() { // logic ... }}) } 

Of course, all these features are actually needed for specific tasks and are very useful.
But which option to choose is not always obvious to the developer, especially for a beginner.


Review code is required


Despite the fact that we use Vuex, I noted for myself that sometimes people find it hard enough not to use data () to be used instead of state.


This is a question of speed rather - it is clear that adding something to data faster, but almost always it turns out that later it will have to be taken out in the state and spend extra time on it.


Perhaps, the situation in projects where there is no review code and there are a large number of juniors without much experience with Vue will be especially sad.


I can assume that working with this code in a few months will be completely unpleasant.


Unit tests


Also, after Angular, it was not very convenient and obviously mocking some things in Jest.
A specific example is local storage. Someone decided to goadling this issue on a githaba .


 Object.defineProperty(window, 'localStorage', { value: localStorageMock, }) 

I did not find the solution beautiful, but as it turned out, there is a more elegant one.


 global.localStorage = localStorageMock; 

Yes, this is not a Vue problem, but an ecosystem problem in comparison with Angular.


In my opinion, precisely such real examples should be described in the documentation.


Cookbook


In general, the guys from Vue know about this problem and solve it by writing a cookbook with recipes .
In fact, this is a set of ready-made solutions for popular tasks.
For example: unit tests ,
validation and work with HTTP .


However, the recipes are still quite basic and are not enough for serious tasks.
Tests are described and for a general understanding of this is sufficient, but the mocking mentioned above will have to be searched for yourself.


I’ll talk about validation later, but the work with HTTP is not precisely described in depth.


I would say that Angular taught me to work with the backend API through services, I consider this a good pattern that greatly facilitates support and reuse of the code.


But since we don’t have the notorious DI, and it’s not very convenient to create service instances, I would like to have a similar pattern in the Cookbook.


For the most part, we have solved this problem by developing local code conventions and best practices. Links at the end of the article


TypeScript


I have already said and written many times about how cool and useful TypeScript is, but the fact is that you need to know how to cook it.


In Angular, everything is tied up with experimental features (decorators), inner classes and hundreds (thousands?) Of unnecessary abstractions.



In Vue, the possible use of TypeScript is much more logical - it only allows you to expand the capabilities of the developer, without having to be tied to certain features of the language.


Problems with TypeScript in Vue


However, to date, using TypeScript with Vue is not always that easy, here are a number of problems we have encountered.


First, they never took my pull request because of their broken tests = (((


The joke, of course, is just my personal pain.


Two approaches


The main problem of TypeScript in Vue I would call the fact that there are two different official approaches to its use .


This is Vue.extend (taipings that come bundled with Vue out of the box and supported along with the main library)


 import Vue from 'vue' const Component = Vue.extend({ ... }) 

and very similar to the Angular decorator vue-class-component


 import Vue from 'vue' import Component from 'vue-class-component' @Component({ template: '<button @click="onClick">Click!</button>' }) export default class MyComponent extends Vue { message: string = 'Hello!' onClick (): void { window.alert(this.message) } } 

Personally, I don’t like the class-component, and for several reasons we use Vue.extend:


  1. The class-component has its own tricks
  2. I want as little as possible to get away from the default ES6 Vue components
    • And use the code directly from the documentation, without the need to edit for TS
  3. It is necessary for the team to understand how Vue works without TypeScript.
    • Especially since most have an angular background.

Other problems


Here are some other problems with TypeScript, of varying degrees of sadness:


  1. TSlint out of the box does not work with Vue - still cannot be run for .vue files . In general, there are solutions through fork-ts-checker, but they are all ugly
  2. ESlint for TypeScript to put it mildly is not super. Both plugin and parser are still under development.
    Many core and vue rules break, but the main problem is that extremely incomprehensible errors occur.
    However, despite this, we use it exactly by disabling broken rules and twisting the necessary ones.
    Link to our ESlint config .
  3. Vuex store is not typed outside, respectively, calls this.$store from the component are possible with virtually any payload

But Vue.extend (), in turn, has some drawbacks:


  1. You can not use as a class (your captain), respectively, no private, static methods, and so on.
  2. Pain with mappers from Vuex ... mapGetters (), ... mapState () and so on. When using these mappers, typing is lost and strange errors appear . We are waiting for the decision to be flooded.
  3. Typing data () is uncomfortable, because this is a function - every time you have to create an interface describing its return value
  4. Honest typing of props is practically impossible at all, since It is necessary to declare a native JS type, and usually a TypeScript interface is expected, but there is an ugly solution with casting

 //      myObjectProps interface MyType = {...} //   data interface MyComponentData = { someBooleanProp: boolean; } export default Vue.extend({ data(): MyComponentData { //    data  return { someBooleanProp: false }; }, props: { myObjectProps: Object as MyType //   TS  }, 

Forms with Vuex


In general, forms are a problem not only for Vuex, but for almost any State Management pattern.
Still, it involves a one-way data stream, and the forms imply a two-way building.


Vuex offers two solutions .


Through binding the value to the state value, and for updating the input event with sending the commit:


 <input :value="message" @input="updateMessage"> 

 // ... computed: { ...mapState({ message: state => state.obj.message }) }, methods: { updateMessage (e) { this.$store.commit('updateMessage', e.target.value) } } 

Or nevertheless use two-sided biding and v-model and the receiving and commit should be performed via a getter and setter:


 <input v-model="message"> 

 // ... computed: { message: { get () { return this.$store.state.obj.message }, set (value) { this.$store.commit('updateMessage', value) } } } 

We think the second option is more convenient and concise, but still very verbose.
Present to describe in a similar way a form with 20 fields or more?
It turns out a huge amount of code for such a seemingly primitive task.


The problem is a little less relevant if you use mappers, namely mapGetters() and mapMutations() ,
but, as I wrote above, they are currently working poorly with TypeScript and had to find another solution.


We wrote a primitive mapper, which adds a getter (getter from state) and a setter (commit mutation):


 static mapTwoWay<T>(getter: string, mutation: string) { return { get(this: Vue): T { return this.$store.getters[getter]; }, set(this: Vue, value: T) { this.$store.commit(mutation, value); } }; } 

It allows you to reduce the amount of code and describe the fields in a similar way:


 stringTags: Util.mapTwoWay<IDatasetExtra[]>(STRING_TAGS, UPDATE_STRING_TAGS) 

And, accordingly, use the v-model :


 v-model="stringTags" 

Validation of forms


What was somewhat surprising after Angular is that there is no form validation out of the box in Vue. Although it would seem, the feature is very popular.


However, it does not matter, there are two most popular solutions for this task.


vee-validate


The first is a very similar mechanism with template-driven forms in Angular - vee-validate .


In fact, you describe all the validation logic in HTML.


 <input v-validate="'required|email'"> 

I would say that this approach is suitable only for relatively small / simple forms.
In reality, validation is often very sophisticated, and it becomes inconvenient to describe everything in HTML.


Plus it doesn't work very well with Vuex.


vuelidate


The second solution is Vuelidate. An incredibly elegant way of validating almost any component — the model itself is validated, not one or the other input.


The funny thing is that before discovering this wonderful package we ourselves had already started writing something similar.


 <input v-model="name" @input="$v.name.$touch()"> 

 import { required, email } from 'vuelidate/lib/validators' export default { data () { return { name: '' } }, validations: { name: { required, email } } } 

I highly recommend, if necessary, the validation of forms immediately consider Vuelidate - it works fine (including Vuex), it is easy to connect and customize.


The main feature / problem Vue


Actually, this is the main problem (?). Vue is only a library, not a heaped all-in-one framework.


Out of the box:



Yes, there are officially supported:



However, with all this, in Vue out of the box there is such a cool built-in stuff like Animation ???


At one time, stumbled upon was somewhat surprised by the rich possibilities for the animation of just about anything.


This is perhaps a much more convenient and powerful toolset than in the same Angular.


A cool example from the documentation :



Nightwatch and e2e


A minor problem, again not directly related to Vue, but which we encountered on a real project.


Out of the box, when generating a project for e2e testing, there is a choice between Nightwatch and Cypress .


Despite the fact that I personally see Cypress as the coolest e2e testing tool for today, there is still no support for browsers other than Chrome.


Therefore, we could not choose it for the combat project - the real customers still use other browsers.


Once our tests began to crash on Linux CI for a completely inexplicable reason (everything was OK on Windows), and the errors were not informative.
Later we managed to find out that the problem is related to hashes (#) in URLs .
URL' vue-router .


, ChromeDriver , Nightwatch ( Cypress TestCafe), "" url :


 .url('data:,') .url(client.globals.devServerURL + `/#/my-hashed-url`) 



Angular boilerplate , , Vue .


, , Developer Experience. , .


, .



Vue — React Native.
.


, Vue NativeScript Vue, , , .
Weex, , .


Performance


. .




: http://www.stefankrause.net/js-frameworks-benchmark7/table.html
( " " ).


: GitLab ,
CodeShip , Alibaba, Xiaomi .


Conclusion


.


— TypeScript Vue , , .


, production.
, , TS Vue, JavaScript.


, , , TypeScript .


Vue , , .


, " ", Tide Vue .


code conventions


, , .
, .



cookbook — , ( ).


Vue seed (TS, Jest, ESlint ..), , Vue CLI 3,
.
Vue CLI 3 .


??

Yes. Thanks for attention.

PS: , Vue — ,


PPS: , () — =(


: https://medium.com/@igogrek/how-i-started-loving-vue-d41c1c8e77e1


')

Source: https://habr.com/ru/post/358766/


All Articles