New Javascript frameworks: ruining house party conversations in San Francisco since the mid 2000’s.
Unfortunately, I do spend just enough time making rough prototypes that jQuery is a headache — anything beyond a simple form / AJAX query quickly becomes a nightmarish bowl of Javascript spaghetti.
Learning your first frontend JS framework with a build chain is an excercise in in realizing that browsers were never really meant for enterprise-grade development, and that what we have today is an absurdly fragmented mess of “tools” used to try to make that experience better.
And yes, this is still how it feels to learn JS in 2017.
Yet the world keeps on turning, and browsers aren’t about to change quickly enough to ignore learning these things. Given that (and armed with a free weekend), my question was, “great, what should I learn?”
Being A Lemming
We developers are a bit like lemmings and like to follow where the bulk of open-source development is going. Following a trendy, well-supported framework gives you benefits like:
- Fewer bugs and richer functionality
- Better ecosystem around community-made plugins
- Roadmap transparency
- More StackOverflow question & answers
- More StackOverflow question & answers
- More StackOverflow question & answers
I kid. Well, only sort of.
The elephant in the room is certainly React. Compared to Vue, React is killing it among serious frontend devs who actually have build chains, transpilers, and other voodoo that require NPM:
Google, tells a similar story:
However among hip GitHub users, we see in the past couple of years Vue growth seems to be accelerating. Looking at stars (made with the fantastic Star History tool) we get rough proxy for popularity with devs:
We see that in the span of three short years, React has captured the focus of frontend devs (edging out Backbone & Angular.js), but the winner of highest rate of growth goes to Vue.js.
Comparing issue close rates on Github:
Framework | Open Issues | Closed Issues | Dangling Issue Ratio |
---|---|---|---|
React | 581 | 3,816 | 0.152 |
Vue.js | 61 | 4,395 | 0.0139 |
Vue.js has a 10x smaller open to closed issues ratio (61 open issues and 4395 closed vs. 581 open React issues and 3816 closed at time of writing), which could suggest a faster rate of improvement and/or a higher level of community input.
So, if it’s not the most popular, why Vue.js?
Well, the point of this post isn’t to convince you Vue.js is better than React or vice versa. Here’s Vue.js’s take and another popular “showdown” article.
There’s excellent reasons to use either. Vue.js is more easygoing and nimble, but giant projects might be better off with React or the wary folks who value the stability of a large company (Facebook) as its maintainer.
Moving on, performance benefits of Vue.js include:
- ~25kB size minified (as opposed to 37 - 48kB with React)
- 2x faster rendering than React on average
Benchmark for rendering a list of 10,000 items 100 times:
In either case, Vue.js is in the top two for frontend JS frameworks and if it’s worth a taste of how to use it, continue on below.
Just don’t bring it up at a house party.
A Taste of Vue.js
Here’s a minimal setup:
<!DOCTYPE html>
<html>
<head>
<script
src="https://npmcdn.com/vue/dist/vue.js">
</script>
</head>
<body>
<div id="myApp">
<p>{{ message }}</p>
</div>
<script>
var application = new Vue({
el: '#myApp',
data: {
message: 'Hello there',
},
};
</script>
</body>
</html>
What’s going on here? Quite simply we’re importing the Vue.js library, binding the application instance to an element in our DOM (using a CSS selector), and rendering some data.
Vue.js is creating a virtual DOM for all the elements to be contained inside #myApp
. This has advantages over operating on the normal, vanilla browser DOM since Vue will now be able to tie together bits of data to elements, intercept events, and render custom elements we create.
Let’s add some event listeners and custom methods.
Adding Listeners, Custom Methods, and Binding to Data
<!DOCTYPE html>
<html>
<head>
<script
src="https://npmcdn.com/vue/dist/vue.js">
</script>
</head>
<body>
<div id="myApp">
<h1>An Example Vue App</h1>
<p>{{ message }}</p>
<input v-model="message">
<button @click="myCoolMethod()">
Click to Alert
</button>
</div>
<script>
var application = new Vue({
el: '#myApp',
data: {
message: 'Hello there',
},
methods: {
myCoolMethod: function() {
alert('Alerts are annoying');
// we could run some asynchronous code here
}
}
};
</script>
</body>
</html>
We added:
@click
to our button: this sets up a click listener and executes the code inside from our application instancev-model
input: this is the way we bind the value of this input to thedata.message
string of our application. You’ll notice if we change the characters in the browser, we change the data in the model, which automatically reacts by re-rendering our<p>
tag! No effort needed!methods
functionmyCoolMethod
Control Logic in our Template
Let’s deal with more complex data and conditionally output a bulleted list with each element using a for loop:
<!DOCTYPE html>
<html>
<head>
<script
src="https://npmcdn.com/vue/dist/vue.js">
</script>
</head>
<body>
<div id="myApp">
<ul v-if="messages.length > 0">
<li v-for="msg in messages">
Message: {{ msg }}
</li>
</ul>
</div>
<script>
var application = new Vue({
el: '#myApp',
data: {
messages: [
'Hello there',
'How\'s it going?',
'What\'s the deal?',
]
}
};
</script>
</body>
</html>
You’ll notice the condition v-if="messages.length > 0"
allows us to put arbitrary conditions inside of the evaluation statement on the custom v-if
directive.
All of these are nice, but how do we deal with reusing elements - what if our data was more complex than a list? What if we wanted object-like encapsulation for each of our data items?
Enter components.
Components
From the Vue.js documentation, a small example with three counters”
<div id="example">
<simple-counter></simple-counter>
<simple-counter></simple-counter>
<simple-counter></simple-counter>
</div>
<script>
Vue.component('simple-counter', {
template: '<button v-on:click="counter += 1"></button>',
data: function () {
return {
counter: 0,
}
}
})
new Vue({
el: '#example'
})
</script>
Here we’ve globally declared a component simple-counter
which we can freely use multiple times in our DOM - each with their own internal state.
If you run this you’ll see that you can individually update counters and see that the <simple-counter>
tags simply get replaced with what’s inside the template
.
This method of using strings as templates quickly gets messy, so we’ll usually use the CLI along with single-file templates.
Getting Organized & Transpiling with the CLI Tool
As you can see, our example applications above are going to get a bit unwieldly as we keep adding data, methods, and logic.
Vue provides a CLI tool (vue-cli
) that helps us set up larger projects. It helps do deployment packaging like combining all our code into a single file and minifying it. We can even write syntactically more palatable JS with ES6 and have it transpiled down to boring old, browser-compatible ES5.
First install the CLI tool and create a project folder:
$ npm install -g vue-cli
$ vue init webpack-simple myproject
We could use a few different types of initialization types, but for this we’ll use webpack
. This command will create a folder like the following:
$ tree -L 2
.
├── index.html
├── package.json
├── src
│ ├── App.vue
│ └── main.js
└── webpack.config.js
Now we can put our components into single-file template .vue
files structured like this:
<template>
<!-- Your HTML elements go here -->
</template>
<script>
export default {
// Your data, methods, etc all go here
// for example, using ES6 syntax for our data object:
data() {
return {
variable: 0,
}
}
}
</script>
<style scoped>
// Any CSS you want applied to ONLY this
// type of component goes here
</style>
Generally we’ll have a root component file called App.vue
and a main JS file that creates our Vue instance. Together the flow looks like:
Our index.html
:
<!DOCTYPE html>
<html lang="en">
<body>
<div id="app">
</div>
<script src="/dist/build.js"></script>
</body>
</html>
Then App.vue
:
<template>
<div class="container">
<!-- ... stuff goes here ... -->
</div>
</template>
<script>
import MyComponent from './components/MyComponent.vue';
export default {
components: {
'my-component' : MyComponent,
}
}
</script>
<style scoped>
</style>
and finally main.js
:
import Vue from 'vue';
import App from './App.vue';
new Vue({
el: '#app',
render: h => h(App)
})
and we run a development server in this directory by running
$ npm install # install node modules locally
$ npm run dev
This not only serves the page on localhost:5000/index.html
, it also starts a hot-reload server so as you edit code, the page updates. No more CTRL+C, up arrow, and hitting ENTER dance everytime you change a file!
Building for Deployment
To actually package up our JS into a single file we use:
$ npm run build
This puts all the JS together in the dist/build.js
folder, and this Javascript file could be uploaded to your static file store or CDN - it’s all you need to run and use everything contained in your project folder created by the Vue CLI tool.
Other Cool Features of Vue
Also know that Vue is quite full-featured and comes with a lot of amazing stuff:
- Communication between components with events
- Custom directives (create your own
v-bind
-type directives) - Filters to apply functions to data:
- Mixins: share code among different components
- Animations: using only minimal CSS
- HTTP requests:
this.$http.get(URL, function(...) { ... });
- Vue Router: for single page applications
- Managing global application state with Vuex (like Flux or Redux)
Wrap Up
This is a good preview of the Vue is, but if you want to learn obviously there’s a lot I didn’t mention here.
I can’t recommend highly enough Maximilian Schwarzmüller’s Udemy class on Vue.js 2.0 (newest version) - I was able to go from never having used a true JS frontend framework or ES6 to being quite comfortable building application and setting up everything in just a weekend. I’d recommend watching at 1.25x speed though.
It’s overall an impressive framework that is light, performant, fully-featured, intuitive, and quickly growing.