YCM Jason

Looks like Vue.js will likely out-star React over the weekend!

original post: https://www.ycmjason.com/blog/2018/06/14.html

It's almost there! It's almost there!!!!

Few weeks ago I published vue-vs-react.

Since the star difference are getting closer and closer (268 stars gap at the moment I am typing this), I decided to add a new feature to my project. Fireworks will explode with a background audio at the moment that Vue out-star React!

You can simply open the website in a tab and when Vue out-star React, you should get notified by the background music!

I am so so so so so excited!

# Things worth mentioning when building this project

# First time using $refs

There isn't many cases of obtaining direct reference to the DOM when using Vue. Most stuff could be easily handled with the power of Vue.

In this project tho, I have an <audio> which will be triggered to play when vue.stars > react.stars. In order to do so, I must get the reference to the element and do elem.play(). The way to get a reference to a DOM in Vue is by adding ref="name". So I just simply did the following (see this line):

<audio src="..." ref="audio"></audio>

Then this.$refs.audio will be pointing to that element! Now I could do this.$refs.audio.play() and this.$refs.audio.pause() inside the component!!!! (see this line)

This make me realise for the first time that $refs could be useful when you want to access the native apis.

The way that I am currently doing is quite hacky. The proper way would probably look something like:

// Audio.vue
<template>
    <audio :src="src" ref="audio"></audio>
</template>

<script>
export default {
    props: ['playing'],
    watch: {
        playing(p) {
            if (p) this.$refs.audio.play();
            else this.$refs.audio.pause();
            // actually I will write: this.$refs.audio[p? 'play': 'pause']();
        },
    },
}
</script>

With this wrapping Audio component, we don't ever need to use $refs anywhere else in the codebase! $refs are low-level stuff and IMO, we should always wrap it around to lift the level of abstractions of the code.

# Vue can update the DOM really quickly

If you have clicked into the website, you might notice the numbers kind of grow towards the number of stars of the repos. This effect is implemented with this TransitioningNumber component.

The way this component work is that whenever the porps.number changes, it calculates the animation frames. The frames is simply a list of numbers ranging from the previous props.number to the current props.number. Since I have set the FPS to 22, the corresponding second per frame would be 1 / 22. To animate this, we can simply change the this.displayNumber from the first frame to the last frame with a timeout of 1 / 22 seconds between each frame. I am surprised how good can Vue handle this and the result looks really satisfying to me.

I will give an example to illustrate the above implementation. Say we want to show transition from 0 to 1000 within 2 seconds. To achieve 22 FPS, we know that we need 22 * 2 = 44 frames. So we will construct a list, frames, with 44 frames ranging from from 0 to 1000. It is obvious that each frame would have step = 1000 / 44 = 22.7272727 ~= 23. Then we construct the list frames = [0, 23, 46, 68, ..., 1000]. Then we set this.displayNumber to each frame with a timeout of 1 / 22 seconds between each frame.

This approach is more of an experiment and does look very naive. I would really appreciate if you could suggest a better approach. Please comment below!

# Firestore is just awesome

In this project I used firebase, in case you haven't already heard, it is basically a backend-as-a-service, you won't need to care anything about the architecture of the server. It allows you to focus on the application logic.

Firestore is a real-time database by firebase. It has a powerful API which includes basic CRUD (create, read, update, delete) operations and subscription to database updates and more!!!! You don't have to set up your own REST API anymore, just use firestore. You won't ever need to setup the very annoying WebSocket anymore, just use firestore! "Amazing! Just do everything for me please!"

Please refer to these two files (1 and 2).

// services/repoSnapshots.js (expanded)
import firebase from 'firebase';

export default {
    subscribe: (fn) => firebase.firestore()
      .collection('repo-snapshots')
      .orderBy("timestamp", "desc")
      .limit(20)
      .onSnapshot(snapshot => fn(snapshot.docs.map(d => d.data()))),
}

// App.vue (<script>)
import repoSnapshots from './services/repoSnapshots.js';

export default {
    ...
    data: () => ({
        snapshots: [],
    }),
    created() {
        repoSnapshots.subscribe(snapshots => this.snapshots = snapshots);
    },
    ...
}

As you can see, the code is insanely descriptive and easy. Although the documentation is not very complete, it takes some time to dig our the method I want. It is still very simple to use.

# Parcel is truly awesome

Vue-cli 3.0 is absolutely amazing. But I think Parcel still is the winner for the most 0-config bundler. This project is so easily bootstrapped thanks to the very powerful Parcel! I don't ever need to worry about adding sass-loader/vue-loader or whatever loader. It just, do it for you! MAGIC!

# Anyways,

I hope you are as excited as I am to see Vue out-starring React and enjoyed reading this post. Please feel free to ask me any questions I would definitely answer if I could. Thanks for reading!