what a vue
an initial look at vue
An initial look into Vue.js, a popular MVVM UI framework, which seems to be going from strength to strength.
background: My goto UI framework is Aurelia, and am interested in how this stacks up.
(if i miss anything tweet me)
TLDR;
- Vue is epic, and is closing the gap to Aurelia
- Developer experience is great.
- Class components are the best way (and will become the defacto)
- I miss the dependency injection, loggers and event aggregator that Aurelia provides
- The 1 file for the Vue, is really nice (enforces smaller components)
code
all code is not production quality.
shout outs to:
- alligator - great vue articles
- class components - by alligator
- why i use class components - since then vue 3 mentioned it will support this as defacto.
- vue 3.0 plans
- what are directives
The App
To enable a smack-down, I mean any observations, we will develop a small simple todo app (surprise!). In addition we can use provided libraries to help highlight how things work in these frameworks.
Vue
Aurelia
setup overview
VueJs | Aurelia | |
---|---|---|
CLI | official | official |
VS Code | Vetur | aurelia |
Chrome | Vue.js devtools | aurelia inspector |
Materialize | Vuetify | Aurelia Materialize Bridge |
Project language | Typescript | Typescript |
bundler | webpack | webpack |
Observations
what should we observe
In this post I wanted to look how vue.js supports the developer, in creating a maintainable application.
- Concepts
- project setup / documentation
- state
- data-binding
- routing
- components
- tools and debugging
as mentioned, we will baseline these observations via comparison, using Aurelia as a yard post.
Concepts
Vue is similar to Aurelia (a component framework with templating/data-binding). It is not like React (where react everything is in Javascript).
Vue has many of the features that Aurelia provides.
VueJs | Aurelia |
---|---|
Components | Components (split into 2 files, .ts / .html) |
Filters | Value Converters |
Custom Directives | Custom Elements |
scoped CSS | scoped CSS |
Slots | Slots |
Data-binding | Data-binding |
Plugins | Plugins |
Dependency Injection | |
Router | Router |
Transitions | Transitions |
Event Aggregator | |
mixins | mixins |
loggers |
For Vue there is a workaround to implement a event bus.
page life cycle
Both frameworks offer places where you can intercept the components life cycle.
VueJs | Aurelia |
---|---|
beforeCreated() | |
constructor() | |
created() | created() |
beforeMount() | bind() |
mounted() | attached() |
beforeUpdate() | |
updated() | |
beforeDestroy() | |
detached() | |
destroyed() | unbind() |
(i have assumed a couple are similar)
project setup / documentation
Vue provides a wizard setup via its Cli, this is comparable to Aurelia’s wizard.
An interesting point during the vue setup was that the routing was an optional extra, I assume this is part of the adoption strategy where you can write 1 page of a legacy app using Vue and transition from there.
The main observation at this point, is Typescript is not the primary language for both frameworks, but its how this is supported by both.
Aurelia has been built with this in mind and provides excellent support, in both intellisense (d.ts files) and documents (all examples are in EsNext and Typescript)
Vue in this version (2.x) offers some TypeScript support, there is intellisense (d.ts files), but not much in the ways of documentation (1 page).
At the time of writing Vue is being re-written from scratch (3.x) in Typescript. The Class way of writing a component will become the defacto, more TS friendly. (from a personal view this seems much cleaner than the current module default).
Other than that the rest of Vue’s documentation is spot on (as too is Aurelia’s)
Structure
Both cli’s provide a starter project structure of which you are free to change as required.
State
Vue’s Class way of writing components makes this very similar to working with Aurelia. If we revert to the current default then we would need to structure our module/typescript-class in a particular way, for example our state would need to be stored in the data attribute.
OLD way (vue)
export default {
//scoped variables in this component
data () {
return {
items: [],
newItemContent: ""
}
},
//rest of the module
}
The developer does not have to manually implement an observer pattern. The ViewModel is modified on the fly with observers, on the properties what are data bound similar again to Aurelia.
New way (vue)
@Component({})
export default class Todo extends Vue {
//the data is now just (natural) properties on the class
items: Array<TodoItem> = [];
newItemContent: string = "";
//rest of the class
}
FLUX state
Although the app does not implement this, it is something that is key to all SPA’s, and from the docs you can see that Vue has Vuex, which integrates with their development browser tool.
According to Aurelia’s docs, the store offered by Aurelia simplifies the solution by missing our the mutation stage/functions.
Data binding
VueJs | Aurelia | |
---|---|---|
text | { {item.name} } |
${ item.name } |
dynamic style | :style="attributeName" |
style="text-decoration:${ item.isComplete ? 'line-through' : ''}" |
dynamic class | :class="[ item.isComplete ? 'strike' : 'no-strike' ]" |
class="${item.isComplete ? 'strike' : 'no-strike'}" |
click function | @click="addItem()" |
click.delegate="addItem()" |
repeater | <v-card v-for="(item, index) in items"> |
<md-card repeat.for="item of items"> |
value binding | v-model="newItemContent" |
value.bind="newItemContent" |
value converter | { { currentDate | dateFormat } } |
${ currentDate | dateFormat } |
(on the double braces, i had to add a space for this bog to parse it correctly)
both support similar capabilities, I found Aurelia being a fractionally more flexible, and i appreciated the use of the ${}
.
My initial small issue I had was the short hand for v-on
and v-bind
in Vue, these are not completely consistent, but is optional.
Vue normal | Vue short-hand |
---|---|
v-bind:disabled |
:disabled |
v-on:click |
@click |
their has been a tonne of thought behind all of these, and the more you use the framework the more this will make sense.
Routing
Not much to mention here, Vue supports this really well, in a very similar way to Aurelia
All you need to do is setup a router and then add <router-view></router-view>
Components
Both these frameworks are just components, which is just epic.
Vue combines all the parts of the component into a single file (the view, view-model and css) which at first I did not like, however its growing on me, as it should make developers consider how large their components are.
Vue component layout, 1 file
<template>
<div>
<!-- the template / view -->
</div>
</template>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
//CSS for this component
.strike {
text-decoration-line: line-through;
}
</style>
<script lang="ts">
import Component from "vue-class-component";
@Component({})
export default class Todo extends Vue {
//impl
}
</script>
The main point which i have already mentioned is using the Class Component which made these experience way better and brought this almost on-par with Aurelia.
Aurelia component layout, 3 files
---todo.html---
<template>
<require from="./todo.css"></require>
<div>
<!-- the template / view -->
</div>
</template>
---todo.css---
.strike {
text-decoration-line: line-through;
}
---todo.ts---
export class Todo {
items: Array<TodoItem> = []
newItemContent: string;
addItem(){
//impl
}
}
Both frameworks provide support for creating re-useable elements/components, one thing i liked better with aurelia was how bindable properties worked.
Vue
---component---
@Component({
props: ['dateTime']
})
export default class MomentAgo extends Vue {
beforeMount() {
//note the <any>this, as the props is not part of this class.
this.momentValue = moment((<any>this).dateTime).fromNow();
//do more things
}
destroyed() {
//do things
}
}
---use---
<moment-ago :dateTime="item.dateTime"></moment-ago>
Note how the Aurelia code is very similar, except for the bindable property is located inside the class, and therefor compiler safe/refactor-able.
Aurelia
----component---
@customElement('moment-ago')
export class MomentAgo {
@bindable value: Date;
bind() {
//cleaner code, and compile safe.
this.momentValue = moment(this.value).fromNow();
//do things
}
unbind() {
//do things
}
}
---use---
<moment-ago value.bind="item.dateTime"></moment-ago>
Tools and debugging
Both have Vs Code and Chrome plug-ins, both are equally comparable.
Vue’s chrome plugin looks amazing, and provide a lot of information.
Aurelia’s plugin is epic too.
Conclusion
Vue is simply epic, and i look forward to V3, with more typescript support.
It is very similar to Aurelia, in terms of concepts, and I was able to create components which had a direct comparable in both applications.
However i do miss some of the things Aurelia provides (dependency injection, event aggregator and logging). In larger SPA’s these features become tools in which support decoupled modular plugins, and make them maintainable.
I did not really look into the plugin support. I was only able to observe a small portion via the Materialize UI plugin, which registered its components globally. this was not enough to make any real observation.
At this point I would strongly recommend people to look at Aurelia, and I would like to see what a Vue person would make of Aurelia.