DEV Community

Cover image for Building a Desktop App with Vue: Vuido
Natalia Tepluhina
Natalia Tepluhina

Posted on • Edited on

Building a Desktop App with Vue: Vuido

Update: Building Vue desktop app with Electron

I love Vue. 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 or NativeScript-Vue; but also there is a way to build desktop apps. You can choose Electron or Vuido 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. 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 library which provides native GUI components for each desktop platform, and the 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 API to fetch actual data.

If you want just to check the final code, it's here.

🛠️ 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 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
Enter fullscreen mode Exit fullscreen mode

Right after an installation is finished, you can find the MainWindow.vue component inside your src folder with the following code:

<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>
Enter fullscreen mode Exit fullscreen mode

If you run build and then start tasks, you will see a window with the very basic desktop app:

Screenshot1

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 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:

<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>
Enter fullscreen mode Exit fullscreen mode

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

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 one! So now our input box looks like this:

<Box horizontal padded>
    <TextInput v-model="query" stretchy></TextInput>
    <Button :enabled="!!query">Search</Button>
</Box>
Enter fullscreen mode Exit fullscreen mode

🔗 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 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.

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

npm install --save axios
Enter fullscreen mode Exit fullscreen mode

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

import axios from 'axios';
axios.defaults.baseURL = 'http://api.openweathermap.org/data/2.5'
const apiKey = process.env.API_KEY;
Enter fullscreen mode Exit fullscreen mode

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

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 = '';
        });
    },
  },
};
Enter fullscreen mode Exit fullscreen mode

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

<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>
Enter fullscreen mode Exit fullscreen mode

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

📦 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 and LaunchUI Packager to package and distribute applications to end users.

I've installed LaunchUI Packager globally:

npm install --global launchui-packager
Enter fullscreen mode Exit fullscreen mode

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

launchui-packager weather-app 1.0 dist/main.min.js
Enter fullscreen mode Exit fullscreen mode

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

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.

Top comments (30)

Collapse
 
ismaelamezcua profile image
Ismael Amezcua

Superb introduction to Vuido. Just a heads up, if your are copy/pasting the code into your application, there is a missing } on the following line:

axios
  .get(
    `/weather?q=${this.query&units=metric&&appid=<YOUR_API_KEY>`,
   )

It should be

axios
  .get(
    `/weather?q=${this.query}&units=metric&&appid=<YOUR_API_KEY>`,
   )

You could also declare a variable for your API key so it would be easier to import from env variables:

const apiKey = process.env.API_KEY;

axios
  .get(
    `/weather?q=${this.query}&units=metric&&appid=${apiKey}`,
   )
Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Thanks for spotting this and for the advice! Fixed ;)

Collapse
 
yunseopkim profile image
yunseop kim

Thank you for this article. If possible, I would like to translate this article and share it with Korean developers, can I translate it?

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Sure, would be happy to see it translated!

Collapse
 
yunseopkim profile image
yunseop kim • Edited

this is the korean translation! :D

Many korean developers like this article!

devtimothy.tistory.com/91

Thread Thread
 
n_tepluhina profile image
Natalia Tepluhina

Awesome! Thank you for you work on this translation =)

Collapse
 
danieljsummers profile image
Daniel J. Summers

Nice writeup! I think your executable is probably bigger because of the Axios library also being included.

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Yes, probably without dependencies it'd be around 20Mb indeed :)

Collapse
 
michalmecinski profile image
Michał Męciński

The Linux and Mac packages are actually bigger, but the Windows 32-bit version is around 20 MB ;)

Thread Thread
 
n_tepluhina profile image
Natalia Tepluhina

Hi Michal! First of all I want to thank you for your work on Vuido and LaunchUI! Awesome projects and awesome documentation!

Indeed, just checked and Windows 32-bit package is 22.4 Mb (probably a bit more for Axios, as mentioned in comments)

Thread Thread
 
michalmecinski profile image
Michał Męciński

And I thank you very much for writing this great article :)

Collapse
 
gergelypolonkai profile image
Gergely Polonkai

This is a really good article, with one thing off: Electron apps are not desktop apps. Please stop suggesting that.

Electron is a huge resource hog. Running three of them easily eats up all my 8GB of memory. It’s not a solution, but a problem. If you want desktop apps, write desktop apps.

Collapse
 
thejaredwilcurt profile image
The Jared Wilcurt

Alternatively, you can use NW.js. It's all the same features as Electron, but uses much less resources. If lower resources are your highest priority though, then go with LibUI-Node/Vuido.

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Well, this is a good point to look at while building an Electron app ;)

Collapse
 
jodyshop profile image
Waleed Barakat

Awesome! I think Vue with be the next big thing :)

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Really hope so :)

Collapse
 
jodyshop profile image
Waleed Barakat

It will be! too many big tech companies use it worldwide!

Collapse
 
thejaredwilcurt profile image
The Jared Wilcurt

You've left out NW.js, which has great Vue support. There is nw-vue-devtools, which unlike Electron is always the latest most up-to-date version of Vue's dev tools. There is Vue-Desktop-Basic, NWjs-Vue, NW-Skeleton, and Vue-NW-Seed for boilerplates. NO ONE should be using Electron. With that sad, glad to see Vuido/LibUI-Node getting some attention.

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Thank you! Will look into it

Collapse
 
cynthiablue profile image
cynthiablue

I am brands new to Vue and am thinking of starting a project for a desktop application using Vue. I also like Quasar and I'm wondering, if I start the project using Vuido will I be able to add Quasar on as well? Thanks.

Collapse
 
kurisutofu profile image
kurisutofu

I was just wondering if it was possible to use Vue with Electron so I'm looking forward to the next article!

Collapse
 
n_tepluhina profile image
Natalia Tepluhina

Yes, it's definitely possible! Will publish it soon

Collapse
 
jenlooper profile image
Jen Looper

Really interesting article! Now I'm wondering what I want to build with Vuido!

Collapse
 
dbelyaeff profile image
Dmitriy Belyaev

It's nice but without an ability to customize interface it's not so good as it could be.