Building a Desktop App with Vue: Vuido
Tags: vue, javascript
Published: 2018-09-03 11:51:02

---
title: Building a Desktop App with Vue: Vuido
published: true
description: You can build not only web apps with Vue framework, but also real desktop applications! In this article we will have a look at Vuido library to create apps with native GUI components
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ns24fpwwd52uu9enkd2y.jpeg
tags: #vue #javascript
series: Desktop applications with Vue
---

**Update:** [Building Vue desktop app with Electron](https://dev.to/vuevixens/building-a-desktop-app-with-vue-electron-3pl) 

I love [Vue](https://vuejs.org/). It's a great framework allowing you to build awesome web applications. But the real magic is you're not limited to web only. You can simply make native mobile applications using [Weex](https://weex.incubator.apache.org/) or [NativeScript-Vue](https://nativescript-vue.org/); but also there is a way to build desktop apps. You can choose [Electron](https://electronjs.org/) or [Vuido](https://vuido.mimec.org/) library for this purpose. In this article I will describe Vuido approach an in the next one I will try to build the same app with Electron.

> Vuido is a framework for creating native desktop applications based on Vue.js created by [Michał Męciński](https://github.com/mimecorg). Applications using Vuido can run on Windows, OS X and Linux, using native GUI components, and don't require Electron.

> Under the hood, Vuido uses the [libui](https://github.com/andlabs/libui) library which provides native GUI components for each desktop platform, and the [libui-node](https://github.com/parro-it/libui-node) bindings for Node.js.

## 💻 What are we going to build

As an example, we will make a simple application checking current weather in the city of your choice. We will use [OpenWeatherMap](https://openweathermap.org/api) API to fetch actual data.

If you want just to check the final code, it's [here](https://github.com/NataliaTepluhina/Vue-Desktop-App/tree/vuido).

## 🛠️ Installation

As stated in Vuido docs, there are some prerequisites to start developing a desktop app. They are different for different platforms:

### 💡Windows
- `windows-build-tools`
- `Visual C++ Redistributable Package for Visual Studio 2013`

### 💡Linux
- `build-essential`
- `GTK+ 3​`

### 💡OSX
- `Xcode`

I was using OSX for development and I've had Xcode installed at this moment.

Also, you will need [vue-cli](https://cli.vuejs.org/) installed (if you're using Vue CLI 3, you will also need `@vue/cli-init`).

To create a new project, run the following command:

```
vue init mimecorg/vuido-webpack-template my-project
```
Right after an installation is finished, you can find the `MainWindow.vue` component inside your `src` folder with the following code:

```html
<template>
  <Window title="some-app" width="400" height="100" margined v-on:close="exit">
    <Box>
      <Text>Welcome to your Vuido application!</Text>
    </Box>
  </Window>
</template>

<script>
export default {
  methods: {
    exit() {
      this.$exit();
    },
  },
};
</script>
```
If you run `build` and then `start` tasks, you will see a window with the very basic desktop app:

![Screenshot1](https://i.imgur.com/zGGTPyv.png)

Now we are ready to build something more entertaining 😅

## 💅 Scaffolding an app

The first thing you need to know about Vuido is it's using native components. So there are neither our familiar HTML tags nor CSS styling - only a set of native GUI components compatible with different desktop platforms. An ppplication built with Vuido will have the native look and feel on each platform.

This may be considered as both advantage and disadvantage - you can't build an application with a very custom appearance but it will be more lightweight and will work faster than the one built with Electron.

The full list of built-in components could be found in [this section](https://vuido.mimec.org/built-in-components) of Vuido docs.

My initial idea was to build an application to show the weather in the city of the user's choice, so I could test simple user interaction and API calls. First thing I needed was actually an input field with a button. Also, I changed a window size to `400x150px`:

```html
<Window title="Weather" width="400" height="150" margined v-on:close="exit">
    <Box padded>
        <Box horizontal padded>
	    <TextInput stretchy></TextInput>
	    <Button>Search</Button>
	</Box>
    </Box>
</Window>
```

To align an input field with a button horizontally and add a padding between them, we need a `<Box>` container with `horizontal` and `padded` attributes. `Box` is similar to HTML `div`, it works as a wrapper to contain and align components.

`TextInput` is an input field, it's `stretchy` attribute means it will stretch to fill available space.

Now our app looks this way:

![Screenshot2](https://i.imgur.com/PFjEZnD.png)

Let's add a `query` property to component data and set it as `v-model` for the input field. Also, we need to disable a button when there is no query string and it was tricky for me because I've tried a familiar `disabled` attribute - but in Vuido you should use [`enabled`](https://vuido.mimec.org/usage/common-attributes) one! So now our input box looks like this:

```html
<Box horizontal padded>
    <TextInput v-model="query" stretchy></TextInput>
    <Button :enabled="!!query">Search</Button>
</Box>
```

## 🔗 Making an API call

Now the idea is to fetch current weather conditions with a given query string as a city.

To get weather data I used the [OpenWeatherMap](https://openweathermap.org/api) API. It provides a lot of different stuff but we need only `Current weather data` chapter. You can check an example of JSON response [here](https://samples.openweathermap.org/data/2.5/weather?q=London,uk&appid=b6907d289e10d714a6e88b30761fae22).

So, in order to start fetching data, we need to add an axios library:

```
npm install --save axios
```

Then import it and set a base URL and OpenWeatherMap API key variable:

```js
import axios from 'axios';
axios.defaults.baseURL = 'http://api.openweathermap.org/data/2.5'
const apiKey = process.env.API_KEY;
```

After this, let's add a bunch of new properties for weather data and a method to fetch it from API:

```js
export default {
  data() {
    return {
      query: '',
      error: false,
      city: '',
      country: '',
      weatherDescription: '',
      temp: null,
      tempMin: null,
      tempMax: null,
      humidity: null,
    };
  },
  methods: {
    exit() {
      this.$exit();
    },
    showWeather() {
      axios
        .get(
          `/weather?q=${this.query}&units=metric&&appid=${apiKey}`,
        )
        .then(response => {
          this.city = response.data.name;
          this.country = response.data.sys.country;
          this.weatherDescription = response.data.weather[0].description;
          this.temp = response.data.main.temp;
          this.tempMin = response.data.main.temp_min;
          this.tempMax = response.data.main.temp_max;
          this.humidity = response.data.main.humidity;
          this.error = false;
        })
        .catch(() => {
          this.error = true;
          this.city = '';
        });
    },
  },
};
```
Now it's time to attach a new method to the button and change the template to show all given data or an error if query doesn't match any of existing cities

```html
<Window title="Weather in your city" width="400" height="150" margined v-on:close="exit">
    <Box padded>
	<Box horizontal padded>
	    <TextInput stretchy v-model="query"/>
	    <Button :enabled="!!query" @click="showWeather">Search</Button>
	</Box>
	<Separator horizontal/>
	<Group margined>
	    <Box padded>
	      <Text v-if="error">There is no such city in the database</Text>
	      <Box v-if="!!city">
	        <Box padded horizontal>
	          <Text stretchy>{{city}}, {{country}}</Text>
	          <Text>{{temp}}&deg;C</Text>
	        </Box>
	        <Text>{{weatherDescription}}</Text>
	        <Separator horizontal/>
	        <Box padded horizontal>
	          <Text stretchy>Min: {{tempMin}}&deg;C</Text>
	          <Text stretchy>Max: {{tempMax}}&deg;C</Text>
	          <Text stretchy>Humidity: {{humidity}}%</Text>
	        </Box>
	      </Box>
	    </Box>
	</Group>
    </Box>
</Window>
```

As you can see, the first box is the input container we've created in the previous chapter. Below there is a `Separator` - a horizontal line to visually separate widgets. Next is `Group` - it's a container which provides a border with a caption around its content.

Inside the `Group` you can see a combination of components you've already seen: `Text` for simple text content, `Box` as a container and `Separator`. Now applicaton looks the following way:

![Screenshot3](https://i.imgur.com/jNwLyGy.png)

## 📦 Packaging

In my opinion, the best and the easiest way to package Vuido-powered application is the one recommended by the library author. He recommends using his own libraries [LaunchUI](https://github.com/mimecorg/launchui) and [LaunchUI Packager](https://github.com/mimecorg/launchui-packager) to package and distribute applications to end users.

I've installed LaunchUI Packager globally:

```
npm install --global launchui-packager
```

Then I ran a following command in the app root folder:

```
launchui-packager weather-app 1.0 dist/main.min.js
```

In the command above `weather-app` is the application name, `1.0` is a version and `dist/main.min.js` is a path to bundle file.

After this a folder with my application! Package size is 39Mb which is a bit more than promised by author (~20Mb mentioned in docs) but not so much anyway.

![Screenshot4](https://i.imgur.com/2dbgk9L.png)

If you try to run it you might notice it's starting really fast (0.1s or so).

## 🌟 Conclusions

**Pros:**

- easy to build
- provides small package size compared to Electron-powered apps
- well-documented

**Cons**

- no cool styles 😕
- still not released (current version is 0.2.0)

Vuido looks like a good option if you need a fast small application with a basic appearance. It has a clear documentation and probably the list of built-it components will grow in the future.