Electron + Vue.js

Kirsten Swanson
Dec 13, 2016 · 5 min read

My first Electron project was creating an application that sets your Mac OS desktop background with an Unsplash image. This project idea was instantiated by my partner I was working with, but I totally loved this idea. Plus, I was super excited to use Unsplash’s API to grab beautiful, high-resolution images. Let’s get started!

We decided to use Vue.js as the JavaScript framework since we’ve already learned React, so we wanted to try a new framework. Also on a side note, I’ve heard great things about the ease of learning Vue.js and how it’s gaining popularity amongst developers. It turns out Vue.js has some great documentation and rumors were correct that Vue.js has a gentle learning curve, especially if you’re already familiar with component structure.

We initially tried to set-up our application with webpack, but were having difficulty communicating between the Electron and Vue.js files. Luckily, we came across an Electron and Vue.js boilerplate that had everything wired up including testing. This boilerplate had the Electron “BrowserWindow” info specified in the electron.js file, whereas typically this file would be called main.js.

However, with this boilerplate the main.js file is the root Vue instance.

The App.js file is a component. It has a child component called “HomePage” that is being imported into it.

The above syntax is using vue-loader, which transforms Vue components into a plain JavaScript module. The HTML needs to be wrapped in <template></template> tags. The JS gets wrapped in <script></script> tags and styles are in <style></style> tags. I typically don’t like in-line styling with JS, but I actually like the layout of the components like this.

Another styling feature I discovered that I enjoyed about Vue styling was scoped css. By specifying scoped in the <style> tag the styling will only apply to the current component. Furthermore, you can add lang="scss" in the <style> tag to state you want to use Sass features. Make sure it’s scss and NOT sass that you declare as the language.

The electron.js file points to the “BrowserWindow” being loaded with the index.html file, with this: mainWindow.loadURL(`file://${__dirname}/dist/index.html`);
The index.html loads the App component and that’s how everything is synced up.

A challenging problem that I needed to reach out for help with was passing props in components. I was trying to pass a function in a child component that stored data in localStorage to the parent component. However, this should have been the opposite with the parent passing the props to the child. We needed the state to change every time a new object was passed into localStorage. We were able to accomplish this by using a lifecycle hook created () (similar to componentWillMount) to achieve this.

export default {
data () {
currentImage: {}
},
created () {
this.getCurrentImage()
},
methods: {
getCurrentImage () {
let imageInLocalStorage = JSON.parse(
localStorage.getItem('currentPicture'))
if(imageInLocalStorage) {
this.currentImage = imageInLocalStorage
}
}
}
}

Comparing data () to the state of React components helped me to understand how props worked in Vue. The above diagram helped me to visually conceptualize how child components received props. In order for the child component to receive props it needs to explicitly state the props it takes in and similarly in React you need to bind the state to the parent. This allows the child to be updated whenever the parent has been updated.

PARENT COMPONENT<template>
<background-preview
v-bind:thumbUrl='thumbUrl'>
</background-preview>
</template>
<script>
export default {
data () {
return {
thumbUrl: ''
}
}
}
</script>
CHILD COMPONENT (BackgroundPreview)<template>
<article
:style"{ 'backgroundImage': 'url(' + thumbUrl + ')' }">
</article>
</template>
<script>
export default {
props: ['thumbUrl']
}
</script>

Additionally, testing was difficult due to routing to the test files. Testing in itself wasn’t too different than other testing frameworks, but the nested file structure complicated the test script. Spectron and Karma were the testing frameworks we used. Spectron reminded me a lot of Selenium because it would open the application and render the DOM features. In addition, since we were writing files after making API calls we used a dependency called “file-bin” as an abstraction for accessing the file system in node.

If I were to burn this project down and start over again I would have set-up the project from scratch instead of using a boilerplate. That’s because I feel like there were dependencies that weren’t necessary for this app and just added more unnecessary complexity. I specifically noticed this in routing to files. There was an extra config.js file that needed to be called everywhere to wire up all the files. Additionally, this impacted the build process and made deployment difficult.

Aside from that this was one of my favorite projects I’ve worked on so far. The capabilities and customization with Electron are endless. It’s exciting to build an application that can rest on your desktop and be built across multiple platforms. Not to mention this app’s functionality will brighten your day. Whether you’re searching for a specific background image or want a random image, it’s fun to change things up! And who can’t resist images like this…

More From Medium

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade