JavaScript is regarded as one of the most commonly used programming languages in the world, as it doesn’t just excel at manipulating elements on the frontend; with this same language, you can create cross-platform mobile applications, develop APIs and work with backend infrastructure, and create desktop applications.
While there have been numerous libraries and frameworks for all of these aspects, Electron stands out when it comes to developing desktop apps with JavaScript, and in this post, we’ll look at how to use Vue with Electron to create our first cross-platform desktop application.
This article assumes the following prerequisites:
Electron is an open source JavaScript framework for building native cross-platform desktop applications with web technologies (HTML, CSS, and JavaScript). This implies that if you have prior familiarity working with these technologies, you can use the same codebase to develop a desktop application for Windows, Linux, and macOS.
Behind the scenes, Electron combines the Chromium engine with Node.js runtime to read and run your codebase as a standalone desktop program. And, to prove its capabilities, popular desktop programs created using Electron include Slack, VS Code, and WhatsApp Desktop.
The following are some of the advantages of using Electron:
Just like anything else, there are some downsides to building desktop applications with Electron too. Some of them include:
If you’ve worked with Vue before, it’s fairly simple to get started with Electron. This is possible with a Vue CLI plugin called Electron Builder, and in the coming sections, we’ll learn how this plugin works by building a sample application that returns a wholesome list of trending movies from themoviedb API.
Here is a preview of what our movie application will look like:
Since Electron builder is a Vue CLI plugin. This means we’ll need to install the Vue CLI itself before we can work with it. To do this run:
npm install -g @vue/cli
Running the above command will install the most recent stable version of Vue CLI, and you can verify that it was successful by running vue -V
, which should print out the installed version of Vue.
Next, we want to create a new Vue application, so go ahead and run the command below to create a new app named vue-desktop:
vue create vue-desktop
The final step is to add the Vue Electron Builder plugin, and we can do this by running the command below:
vue add electron-builder
This will ask you for the version of Electron you want to add to this Vue project, and once you’ve done so, you should see a success message indicating that Electron Builder was installed. You can then launch the app by running:
npm run electron:serve
And you should see an output similar to the screenshot below:
Closing the dev tool, you should see the complete preview of the application, like in the image below:
When you open the project folder in your preferred text editor, you should be presented with the following files and directory as shown in the image below. And if you’ve worked with Vue CLI in the past, you will notice that the file structure is pretty much the same. The only change is the addition of a new background.js
file, and this file is responsible for running our Vue application as a stand-alone desktop application.
In this file, you can configure the default width and height of the window the application launches with, set the application title, add an auto-update feature, among other things.
Now that we’re up to speed with Vue Electron Builder, let’s go ahead and start building our trending movie application.
The first step is to open up public/index.html
and add an entry for Bootstrap and Font Awesome in the head section, like in the code below:
... <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" /> <link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css" /> ...
Next, in the src/components
folder, create a new file called MovieCard.vue
and paste the following code into it:
<template> <main> <div class="card mb-4 shadow-lg border border-secondary bg-dark text-light"> <img class="card-img-top" :src="'https://image.tmdb.org/t/p/w500/' + movie.poster_path" alt="Card image cap" /> <div class="card-body"> <p class="card-text">{{ movie.title }}</p> <div class=""> <div class="d-flex justify-content-between align-items-center"> <div class="btn-group"> <button type="button" class="btn btn-sm btn-outline-secondary"> <i class="fas fa-heart"></i> </button> <button type="button" class="btn btn-sm btn-outline-secondary"> <i class="fas fa-plus"></i> </button> </div> <small class="ms-auto text-muted" >Rating {{ movie.vote_average }}/10</small > </div> </div> </div> </div> </main> </template> <script> export default { name: "MovieCard", props: { movie: { type: Object, required: true, }, }, }; </script>
Here, we have created a MovieCard
component that accepts a prop containing all of the details for each movie. The next step is to delete all of the code contained in src/App.vue
and update with the following:
<template> <div id="app"> <div class="container"> <div class="text-center"> <h2 class="text-center mt-5">Trending Movies 🍿</h2> <p>Keep up with the hottest movies that are trending this week.</p> </div> <div class="my-4"> <a href="#" class="mx-3 h4"> Trending today</a> <a href="#" class="mx-3 h4">This week</a> </div> </div> </div> </template>
At this point, if we run our application, we should have the following output:
The final step is to define a method that fetches the most popular movies from the TMDB API. This process would require you to create a free account with them to retrieve your API key.
To do this, update src/App.vue
with the following code:
<template> <div id="app"> <div class="container"> <div class="text-center"> <h2 class="text-center mt-5">Trending Movies 🍿</h2> <p>Keep up with the hottest movies that are trending this week.</p> </div> <div class="my-4"> <a href="#" @click="getTrendingMovies('day')" class="mx-3 h4"> Trending today</a > <a href="#" @click="getTrendingMovies('week')" class="mx-3 h4" >This week</a > </div> <div class="row" v-if="movies.length > 0"> <div class="col-md-3" v-for="(movie, i) in movies" :key="i"> <movie-card :movie="movie" /> </div> </div> </div> </div> </template> <script> import MovieCard from "./components/MovieCard.vue"; export default { name: "App", components: { MovieCard, }, data() { return { movies: [], apiKey: "YOUR_API_KEY_HERE", }; }, methods: { getTrendingMovies(category) { return fetch( `https://api.themoviedb.org/3/trending/movie/${category}?api_key=${this.apiKey}` ) .then((response) => response.json()) .then((data) => { this.movies = data.results; }); }, }, mounted() { this.getTrendingMovies("day"); }, }; </script>
Here, we imported the MovieCard
component we created earlier in the script section, and we also added a new method, getTrendingMovies()
, which is responsible for loading our movies from TMDB API, and we then ran this function in the mounted hook.
And a small change to our markup is looping all of the results returned from TMDB into our MovieCard
component.
If we refresh our application at this stage, everything should work fine, and you should have an output similar to the image below:
The Electron icon is set as the default icon for your app, and most of the time, you’ll probably want to set your custom icon. You can simply update the app icon by adding a new icon entry in the newBrowserWindow()
method present in background.js
like below:
... const win = new BrowserWindow({ width: 800, height: 600, title: "Trending movies", [+] icon: "./path/to/icon.png", ...
Compiling our application as a stand-alone executable file is straightforward. We can do so by running the command below:
npm run electron:build
Keep in mind the executable app that is generated is dependent on the operating system you’re working with. However, Electron Builder allows you to define which platform (or platforms) you want to generate executables for. Available options include Mac, Win, and Linux.
This means to build the Linux version of your applications, you’ll run the following command:
npm electron:build -- --linux nsis
Throughout this tutorial, we’ve looked at how to use Electron and Vue to create a cross-platform desktop application. We also built an example trending movies application to understand how things worked. And the code for the complete application can be found here on GitHub.
If you enjoy reading the article, do leave a comment below!
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps, including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to implement one-way and two-way data binding in Vue.js, using v-model and advanced techniques like defineModel for better apps.
Compare Prisma and Drizzle ORMs to learn their differences, strengths, and weaknesses for data access and migrations.
It’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
4 Replies to "Building an app with Electron and Vue"
great article, help me a lot.
May I know how to make the preload.js work?
In vue.config.js file:
const { defineConfig } = require(‘@vue/cli-service’)
module.exports = defineConfig({
transpileDependencies: true,
pluginOptions: {
electronBuilder: {
preload: ‘src/preload.js’,
// Or, for multiple preload files:
// preload: { preload: ‘src/preload.js’, otherPreload: ‘src/preload2.js’ }
}
}
})
This is a great introduction to electron js.
Hello, i just followed this tutorial. Everything worked perfectly. But the build command isn’t working.
this is the error i’m getting
Get “https://github.com/electron/electron/releases/download/v13.6.9/electron-v13.6.9-win32-x64.zip”: proxyconnect tcp: dial tcp :0: connectex: The requested address is not valid in its context.
github.com/develar/app-builder/pkg/download.(*Downloader).follow.func1
/Volumes/data/Documents/app-builder/pkg/download/downloader.go:206
github.com/develar/app-builder/pkg/download.(*Downloader).follow
/Volumes/data/Documents/app-builder/pkg/download/downloader.go:234
github.com/develar/app-builder/pkg/download.(*Downloader).DownloadNoRetry
/Volumes/data/Documents/app-builder/pkg/download/downloader.go:128
github.com/develar/app-builder/pkg/download.(*Downloader).Download
/Volumes/data/Documents/app-builder/pkg/download/downloader.go:112
github.com/develar/app-builder/pkg/electron.(*ElectronDownloader).doDownload
/Volumes/data/Documents/app-builder/pkg/electron/electronDownloader.go:192
github.com/develar/app-builder/pkg/electron.(*ElectronDownloader).Download
/Volumes/data/Documents/app-builder/pkg/electron/electronDownloader.go:177
github.com/develar/app-builder/pkg/electron.downloadElectron.func1.1
/Volumes/data/Documents/app-builder/pkg/electron/electronDownloader.go:73
github.com/develar/app-builder/pkg/util.MapAsyncConcurrency.func2
/Volumes/data/Documents/app-builder/pkg/util/async.go:68
runtime.goexit
/usr/local/Cellar/go/1.16.5/libexec/src/runtime/asm_amd64.s:1371
Although i’ve search online and i haven’t seen any solution yet. Please can you help me out