This tutorial is out of date and no longer maintained.
Electron makes it easy to create cross-platform desktop applications with JavaScript. As it uses the Node.js runtime, we have the luxury of using any frontend framework we want! In this article, we’ll be looking at getting up and running with Vue and Electron to create our own applications.
To get started, run the following in your terminal:
- npm install vue-cli -g
Use the electron-vue
starter and create a my-todos
project:
- vue init simulatedgreg/electron-vue my-todos
You’ll then be asked some questions about your project, fill them in to generate the config file:
- Application Name > my-todos
- Application Id > com.example.yourapp
- Application Version > 0.0.1
- Project Desription > Manage your Todos with Vue and Electron
- Use Sass / Scss? Y
- Select plugins to install > Axios, vue-electron, vue-router, vuex, vuex-electron
- Linting with ESLint? > N
- Unit testing with Karma + Mocha? N
- End to end testing with Spectron + Mocha? N
- Which build tool would you like to use? > electron-builder
- Author > Paul Halliday
After filling in the above (you can switch some steps out if you want, most of it is personal preference), we have a folder named my-todos
with our project inside. Install the dependencies and then open this with your favorite editor:
Note: If you’re a Windows user, you may need to follow the steps outlined here prior to continuing.
Navigate to the directory:
- cd my-todos
Install the packages:
- npm install
Run the server:
- npm run dev
If we’ve done everything correctly at this stage, we should be greeted with a macOS application that contains information about our project:
Most of our work will be done inside of the src
directory, and I’d like to bring your attention to the main
and renderer
folders.
Main houses index.js
and index.dev.js
, files that are related to the main process. This is things such as creating a new BrowserWindow
with dimensions, listening for app-wide events, and so on.
Renderer is where we keep our Vue application and can be thought of as the directory for our frontend code.
Note: For more information on the Electron architecture and the differences between the main and renderer process, visit this page.
In order to get a feel for how Electron works, let’s visit src/main/index.js
and see how our main page is defined:
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080`
: `file://${__dirname}/index.html`
function createWindow () {
mainWindow = new BrowserWindow({
height: 563,
useContentSize: true,
width: 1000
})
mainWindow.loadURL(winURL)
mainWindow.on('closed', () => {
mainWindow = null
})
}
app.on('ready', createWindow)
The BrowserWindow
object can be used to display a new browser window (as the name suggests), and we’re using it to open index.html
when the application is ready. In turn, this will start our Vue app, giving us the ability to hook into native desktop features.
Now that we know how the Vue application is started, let’s take a look at the defined routes within our application. Head over to src/router/index.js
:
export default new Router({
routes: [
{
path: '/',
name: 'landing-page',
component: require('@/components/LandingPage').default
},
{
path: '*',
redirect: '/'
}
]
})
As we can see, the LandingPage
component is defined as the default route for our application. We can therefore edit or create a new routes
object with our own components in the future.
In order to get Vuex to work with our Electron project, we’ll need to provide a path to our store within src/main/index.js
:
import { app, BrowserWindow } from 'electron';
import '../renderer/store';
We can then make a new Store module named Todo.js
within src/renderer/store/modules
:
import uuid from 'uuid/v4';
const state = {
todos: []
};
const actions = {
ADD_TODO ({ commit }, name) {
console.log(name);
commit('ADD_TODO', name);
},
COMPLETE_TODO ({ commit }, id) {
commit('COMPLETE_TODO', id);
},
CLEAR_TODOS ({ commit }) {
commit('CLEAR_TODOS');
}
};
const mutations = {
ADD_TODO (state, name) {
state.todos = [ ...state.todos, { id: uuid(), name } ];
},
COMPLETE_TODO (state, id) {
state.todos = state.todos.filter((todo) => todo.id != id);
},
CLEAR_TODOS (state) {
state.todos = [];
}
};
export default {
state,
actions,
mutations
};
We’re using the third-party uuid
module to generate new IDs for each Todo.
Install that via npm:
- npm install uuid
Finally, we can edit our LandingPage.vue
component to include our small Todo list:
<template>
<div class="container">
<div>
<input
class="todo-input"
type="text"
v-model="todoItemName"
placeholder="What are you doing today?"
@keyup.enter.prevent="addTodo"
>
</div>
<div class="todos">
<ul>
<li
class="todo-item"
v-for="todo in todos"
:key="todo.id"
@click="completeTodo(todo)"
>{{todo.name}}</li>
</ul>
</div>
<button class="clear-all" @click="clearTodos" v-if="todos.length > 0">CLEAR ALL</button>
</div>
</template>
<script>
import { mapState } from "vuex";
export default {
data() {
return {
todoItemName: ""
};
},
methods: {
addTodo() {
this.$store.dispatch("ADD_TODO", this.todoItemName);
this.todoItemName = "";
},
clearTodos() {
this.$store.dispatch("CLEAR_TODOS");
},
completeTodo(selectedTodo) {
this.$store.dispatch("COMPLETE_TODO", selectedTodo.id);
}
},
computed: {
...mapState({
todos: state => state.Todo.todos
})
}
};
</script>
<style>
.container {
height: 100vh;
text-align: center;
background-color: #30336b;
}
.todos {
overflow: scroll;
height: 70vh;
margin-top: 20px;
}
.todo-input {
font-size: 36px;
width: 90vw;
border: 0px;
outline: none;
padding-top: 20px;
text-align: center;
background-color: transparent;
color: white;
}
.todo-item {
font-size: 24px;
padding: 10px 0px;
color: white;
}
.clear-all {
border: 1px solid white;
background: transparent;
color: white;
margin-top: 20px;
padding: 20px;
font-size: 18px;
}
::placeholder {
color: white;
}
</style>
As this is a demonstration app, I’ve decided to not componentize this further. This finally gives us the following:
As we’re using electron-builder
to build our application, we can run the following:
- npm run build
If we look in our package.json
, we can also see that we have a variety of other commands at our disposal:
- npm run build:dir # this builds an app without an installer
- npm run build:clear # deletes all builds from the build folder
- npm run build:web # builds for web platform
This can be further customized inside of package.json
by editing the following object:
"build": {
"productName": "my-todos",
"appId": "com.example.yourapp",
"directories": {
"output": "build"
},
"files": [
"dist/electron/**/*"
],
"dmg": {
"contents": [
{
"x": 410,
"y": 150,
"type": "link",
"path": "/Applications"
},
{
"x": 130,
"y": 150,
"type": "file"
}
]
},
"mac": {
"icon": "build/icons/icon.icns"
},
"win": {
"icon": "build/icons/icon.ico"
},
"linux": {
"icon": "build/icons"
}
},
The results of our built application can be found in the build/mac
or build/platform
folder.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!