Vue.js First Impressions

December 21, 2018

Seen the hype, read the stories and so forth. I thought it was about time to pick it up and see what it’s all about. Here are my impressions after a couple of days implementing a very simple file-based gallery for our family photos.

For more on Vue.js see: https://vuejs.org/

Personally I don’t have any extensive web application experience. I’ve written a few simple and one large application throughout the years. Previously I’ve used ReactJS for my projects, so I might be biased just because I know it.

#Project Target Use Vue.js as a front-end for a photo gallery. The gallery is very simple. There is a main page showing various sub-galleries by name and each sub-gallery is filled with thumbnails. Clicking on a thumbnail shows the full photo.

There are only three pages.

  • Main list of galleries, divded per year (server sends the data this way anyway)
  • Page with thumbnails
  • Page with the photo

#Dev setup For any given project I like a certain setup.

  • I want my builds driven by makefiles, as this integrates nicely with my CI pipeline
  • I use Code or Sublime for code editing
  • For web I tend to use Webpack & friends
  • I don’t use the CLI tools provided by the frameworks

Setting up Vue.js for this target environment was not an issue. Everything worked out fine. Made some common misstakes like no alias for vue.esm.js for development, but basically all answers were easy to find.

#Applicaiton layout I have a main applicaiton (app.vue) which is created by index.js.

import Vue from 'vue'
import App from './app'


Vue.config.productionTip = false

new Vue({
    el: '#app',
    template: '<App/>',
    components: { App }
})

Straight forward and no fuzz. The index.html file basically just creates a div with the id app and we hook ourselves up to it.

  <body>
    <div class="app_container" id="app">
      <script src="gallery.bundle.js"></script>
    </div>
  </body>

#Components After playing around with Vue.js for half a day I decided to use the component model for my code. Basically there are two ways of writing components. One is like the ‘app’ is written, where the component is declared within the JS code. The other where you use sections in a file and a pre-processor to transform it. This is all handled by the vue loader plugin for WebPack and nothing we need to worry about.

Vue.js components files have multiple sections. I’ve only used the following (no clue if there are more):

  • template, where you place the HTML for your component
  • style, the CSS for the component
  • script, the java script / code for your component

A component may look like this simplified version of the ViewImage.vue component:

<template>
    <div class="page-container">
        <div class="photo-container">
            <img :src="url" />
        </div>        
    </div>
</template>
<style>
.page-container {
    display: flex;
    flex-direction: column;
    margin: 2px;
}
.photo-container {
    display: flex;
    justify-content: center;
    align-content: stretch;
    border: 1px solid black;
    background-color: black;
}
</style>
<script>
import BackendAPI from '../api.js';

export default {
    props: {
        image: {
            Type: Object,
            Required: true
        },
        gallery: {
            Type: Object,
            Required: true
        },
    },
    data: function() {
        return {
            url: ""
        }
    },
    created: function() {
        this.url = "/api/image/"+this.gallery.Name+"/"+this.image.Name;
    },

    methods: {
        onClickBackToGallery() {
            this.$emit('image-close');           
        }
    }
}
</script>

#Application I created one component for each page (gallery listing, thumb nails, single photo), tested them out and it all worked fine. This was very quick and easy.

When it was time to tie everything together I started running into problems. I completely failed when I dynamically changed which of the three components to render. I could get them to render but then I didn’t receive any callbacks/events from the rendered component.

Basically I tried the following (template section of app)

<component :is="currentView" @some-event="onEvent"></component>

This managed to render the component. But when the component tried to send a message nothing got invoked.

// This message never found it's parent
this.$emit('some-event')

Event after a substantial amount of googling and reading I was failing. I found a lot of ‘tabbed navigation’ examples out there. But none of them sent messages from the tab-view back to the App (holding the tab’s). The problem was not to switch component - that worked fine. The problem was passing messages back from the component to the application in order to handle the view state.

Instead I settled for what I believe is the uglier solution, using v-if statements for the HTML tags in the template.

    <div id="root-container">
        <div v-if="state==1">
            <GalleryListing @view-gallery="onViewGallery"></GalleryListing>            
        </div>
        <div v-if="state==2">
            <GalleryView :gallery="gallery" @view-photo="onViewPhoto" @view-galleries="onViewGalleries"></GalleryView>
        </div>
        <div v-if="state==3">
            <ImageViewer :gallery="gallery" :image="photo" @image-close="onClosePhotoViewer"></ImageViewer>
        </div>
    </div>

Similar code in React would look like.

function Render() {
    if (state === 1) {
        // onViewGallery to change state
        return (<GalleryListing onViewGallery=this.onViewGallery />)
    }
    if (state === 2) {
        // onViewPhoto to change state
        return (<GalleryView onViewPhoto=this.onViewPhoto />)
    }
    if (state === 3) {
        return (<PhotoView />)
   }
}

At the end I got it to work, and I am pretty happy with the result.

#Like/Dislike

##What I liked

  1. Declaration of props should write all meta-data directly. This is really good, keeps it close to the declaration and makes it easy to find. In ReactJS this is kept separate (like a header file or section) which makes it teadious to write and easy to forget.
export default {
    props: {
        gallery: {
            Type: Object,
            Required: true
        }
    }
}
  1. Styling close to the component. The Vue.js components have a ‘style’ section which makes styling sit very close to the HTML. This speeds up the development quite a bit. Like this very much.

##What I didn’t like

  1. Repeating

Why do I need the component section in the export object?

    import GalleryListing from './Components/GalleryListing.vue'
    import GalleryView from './Components/GalleryView.vue'
    import ImageViewer from './Components/ImageViewer.vue'

    export default {
        components: {
            GalleryListing,
            GalleryView,
            ImageViewer
        },

It is utterly redundant.. Perhaps it’s not needed???? If optional (for aliasing purposes or something) that would be fine. But in the general case, this is just simply redundant. The vue-loader anyway does magic, why not grab the import statements and add them to the component list anyway (if they are Vue components). Heck it could even analyze the template section, figure out what to expect and check that you import everything properly. Then at the end automatically add it to the component object. Note - bare JS classes/functions/etc are not required in the components object.

I understand why we need the ‘components’ list of objects. But this could anyway be handled automatically with an optional ‘overloading’ - and merged by the Vue loader.

  1. Magical HTML attributes.

I know others have this aswell (Angular being pretty prominent) but for me this goes against one of the objectives of Vue.js - “you don’t need to learn another language to change the HTML”. This is simply not true. You need to know quite a bit of Vue.js to understand how to design your templates and pages. Perhaps not a language but there are quite a bit of quirks and tricks you can do with the attributes.

        <div v-if="state==3">
            <ImageViewer :gallery="gallery" :image="photo" @image-close="onClosePhotoViewer"></ImageViewer>
        </div>

It even has some short-hand to avoid writing them ‘v-bind’ for instance.

  1. Lack of classes

Ok, I am a backend developer. I like my encapsulation. I also know there are extensions to get VUE mapping to ES2015+ classes. But this for me is just ‘ugly’. I rather like the ReactJS component object way with proper class functions.

Final words

All in all I had a pleasent experience. Vue.js was easy to use and easy to get going with. I acknowledge that it is probably me rather the framework having problems with message routing. I can see myself using Vue.js for smaller projects. It’s easy to create objects and pages. The components I wrote worked fine basically on first try. The division of HTML and Javascript (as opposed to ReactJS) also makes it hard for me. There is logic in several places. For larger projects I will probably stick with ReactJS for the time being.

I would really like to try SSR with Vue to see what can be done with. But that’s for another time.

Final Final Words

While proof reading this I stumbled upon the render-functions in Vue. Perhaps that’s what I should have used for my dynamic component case in the main App.vue object. And maybe I should try the JSX version as well.


Profile picture

Written by Fredrik Kling. I live and work in Switzerland. Follow me Twitter