Terra Incognita: An App Using Vue.js and Electron
Talk to anyone that has been through the curriculum at Turing School of Software and Design, and they’ll be quick to tell you that no project that you’re given is particularly “easy.” Whether it’s learning a brand new technology, or taking an even deeper dive into a language you’ve used in the past, the expectations are always set dauntingly high. Where this gets particularly interesting, however, is when your instructors present you the opportunity to work with two new, budding technologies that you’ve never worked with before…in the same project…and you (somehow) take them up on that. For my partner and I, that project was to create a music player using both Electron and Vue.js. I won’t go too much into the details of the player itself, but in order to clarify why we chose the technologies we did, I think it’s important to highlight a few of the design decisions that went into our app.
First and foremost, my partner and I wanted to model our app off of the 90's media player, Winamp. At its roots, Winamp is a customizable media player that allows users to create and maintain playlists on their desktop. Think of it as a precursor to iTunes, but with much more flexibility in regards to layout and design. We both had a fair amount of nostalgic respect for this classic player, and decided that it would only be right to treat it as the inspiration for our app moving forward. Due to Winamp strictly functioning as a desktop application, this naturally led to us wanting to use Electron as part of our code base.
For those that are not familiar with it, Steve Kinney describes Electron as “a framework for building cross-platform desktop applications with web technologies.” Some examples of Electron in the wild are Atom, Visual Studio Code, Slack, along with many others. We decided to use this framework not only because it gave us the ability to create a desktop application, but also because it would provide us with fairly easy access to the file system — which is imperative when you want your users to be able to add their own media files. As Steve’s quote mentions, all this left us with was choosing a web technology to use in congruence with Electron, and for that, we decided to give Vue.js a shot.
I think it would be fair to say that in the front end program at Turing, we work quite extensively with React. It’s the first framework we learn, we have best practices constantly (attempted to be) drilled into our brains, and we’re also expected to use Redux when applicable. Despite all of that, my partner and I both had another former student and friend give us the hard sell on Vue, and the points he made warranted further investigation. So after some research, we decided that we would break from tradition and use Vue as our web technology for this project. The main selling points being:
- Vue 2.0 is heralded as one of the fastest available frameworks
- The ability to pick up the syntax quickly and painlessly
- The chance to be able to build an app in something new and unfamiliar
- The growing demand for Vue developers worldwide
After this decision was settled, we were off to build Amptron, and never felt the need to look back.
As mentioned previously, this post is less about the app itself, and more about the process and technologies used to bring it to life. With that being said, there is one point of interest (and contention) that we ran into while building our music player that I would like to focus on. A vital part of any music player is, as you might have guessed, actually being able to add a song and then have it play. Because Electron allows you to write a few small functions to access your file system, we thought adding a song to a playlist would be a pretty straight forward process…turns out we were incredibly wrong.
The issue with adding a song was not at all with accessing the file itself with Electron. As we had guessed, this was pretty manageable. What we had found is that we could create a new audio instance and pass it a file for its source with a format of `file://filepath/song.mp3`. The real trouble, however, occurred when we were then trying to play that file using HTML5 audio. The issue that arose was that although Electron packages with Chrome, which in turn guarantees us access to HTML5, Chrome was actually unable to gain access to our file in the same way as Electron did, causing our player to not work.
In order to resolve this, we decided we would need to create a DataUrl and pass it to the audio element as its source. To solve this, we settled on using the NPM DataUrl package in order to convert our files. The function returns a promise with the DataUrl after the song is converted:
At this point, the only other thing we needed was a file path. To give the user the ability to pick a song, we created a function in the Main Process of our Electron app:
Dialog is provided by Electron, and, in our case, gives us a method that lets the user open a file that they want to add to their playlist. The “filters” array gives us the ability to determine what types of files are “acceptable” for our app to open. Although we only allowed mp3s for this project, Electron provides the flexibility for many other types of files to be added (such as flac, mp4, etc.). More information on dialogs can be found here.
The next thing we needed to do was grab the songs duration, as well as any information in regards to the artist, album, track title, and track number. In order to do this, my partner and I used mp3-duration to (shocker!) grab the duration of the song. From there, we used id3js to parse the id3 tags from the file we were passing in so that we could grab the other artist information off of it.
Lastly, we used ES6 promises to pass an empty object and file path to the previously created helper functions. We then resolve the promise, which leaves us with a song object that will be added to our playlist.
Once this had been completed, our song object then contained all the necessary information we would need in order to render it in the playlist. Playing the song is now just a matter of fetching the DataUrl from the function by passing it the file path of the song we want to play. This ensures that we’re only generating and using one DataUrl at a time, which in turn keeps memory usage low.
Reflecting back on this project, there was a lot to be happy about. Other than the bottle-neck that occurred with using HTML5, obtaining mp3s from the file system with Electron was as smooth as expected. Using Vue turned out to be a great experience, as it was everything it was advertised to be. If given the opportunity, I would definitely use it again. If there was anything I could go back and change, however, it would be the way that we spun up our app.
To get our app off the ground, we used the Electron-Vue boilerplate by Simulated Greg. My issue with this boilerplate has little to do with how it actually operates, and more with how much it actually does for you. It created our app almost seamlessly, wiring up Electron and Vue to the point that we really only had to change one or two things before we were ready to go. Despite this, the problem with this approach was that this boilerplate presented us with a lot of awesome tools that we were, inevitably, never going to use within the confines of a one week project. For example, as much as I would have liked to experiment with Vuex, there simply wasn’t enough time to implement something like this given our time constraints. In addition to providing us with a surfeit of tools, the other problem — from a learning perspective — was how well this wired things up for us. If I could go back, I would prefer to wire our app up from scratch, in order to have a better understanding of exactly how everything is interacting with each other. I feel as though I lost out on some learning opportunities by having all of this done for me, as it prevented me from writing more in Electron and forcing me to connect these two frameworks on my own (which I would eventually have to do with Electron and React in a later project). In addition, all of the unused tools mentioned earlier also caused issues when it came time to deploy. Using the boilerplate made it difficult to troubleshoot where the issue was coming from since we didn’t connect the technologies ourselves. Overall, however, the approach of using the electron-vue boilerplate is a great way to go if you already have a decent to solid understanding of both of these frameworks.