What does you do, when you need a desktop version of your existing SPA web app? 💡
Tags: go, webdev, node, tutorial
Published: 2020-02-17 06:38:59

## Introduction

Well, hello! Today is good day, which means it's time for a interesting story for your project this week! 😅 Alright, without too much _foreplay_, let's get started.

### 📝 Table of contents

- [What have we got yet?](#ch-1)
- [What's to be done?](#ch-2)
- [Trials and errors](#ch-3)
- [Golang way](#ch-4)
  - [Hints for macOS](#ch-4-1)
  - [Windows 10 problem](#ch-4-2)
- [What's next?](#ch-5)
- [Questions](#ch-6)
- [Exercises](#ch-7)

<a name="ch-1"></a>
## What have we got yet?

Let's imagine, that we **already have** a well working SPA web application in production. Let it be a simple service for listening to _podcasts_ on all kinds of development topics. And your client is **satisfied**...

![fiber rest api](https://dev-to-uploads.s3.amazonaws.com/i/vz7nujouuuz9g5wztyub.png)

💥 One day, your client comes to you and asks you to develop a **native version** of his website for macOS, Windows 10 and Ubuntu Linux. But web app have frontend on **Svelte**, which successful works with REST API, based on **Fiber**.

> — What's Fiber? 😐
>
> _Fiber is a web framework that was inspired by Express.js and based on Fasthttp, the fastest HTTP engine written on Go. The framework was designed to simplify the process of fast development of high-performance web applications with zero memory allocation._
>
> If you interested, please go to Fiber [documentation](https://fiber.wiki), [repository](https://github.com/gofiber/fiber) or my own introduction [article](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) for more details!

Yeah, maybe a little _unrealistic_ situation, but we're still dreaming! 😁

<a name="ch-2"></a>
## What's to be done?

✅ App must run in its own system window.
✅ App must support for all media keys on keyboard.
✅ There must be a single code base with web version of app.
✅ Development and maintenance of app should not take too long time.

<a name="ch-3"></a>
## Trials and errors

Yep, you may take something, like [Electron](https://github.com/electron/electron), but this will broke 3 and 4 rules above and will mean, that you'll have to **translate** all entire code base of your SPA (remember, already working in the production) to Electron.

![electron](https://dev-to-uploads.s3.amazonaws.com/i/1bw64vys60lbodlbrc5u.png)

If we developed our web app **from scratch**, this approach would be one of _the best_, but we have what we have. Such an approach would be longer and more expensive, than described below.

<a name="ch-4"></a>
## Golang way

As you might have known from my [previous article](https://dev.to/koddr/how-to-create-a-native-macos-app-on-go-golang-and-react-js-with-full-code-protection-part-1-463k), Go has a good package for displaying web pages [zserge/webview](https://github.com/zserge/webview). Also, we will need a tool to cross-compiling for all necessary operating systems — XGO ([karalabe/xgo](https://github.com/karalabe/xgo)).

So, here's what we need to do 👇

- Install packages:

```bash
$ go get -u github.com/zserge/webview
$ go get -u github.com/karalabe/xgo
```

- Write simple Go code:

```go
package main

import "github.com/zserge/webview"

func main() {
	// Define webview settings
	settings := webview.Settings{
		Title:     "SPA Desktop App",     // title for window
		URL:       "https://example.com", // open URL
		Width:     1280,                  // window width (px)
		Height:    720,                   // window height (px)
		Resizable: true,                  // enable resize window
		Debug:     false,                 // disable debug
	}

	// Create new webview app with settings
	window := webview.New(settings)

	// Run webview app
	window.Run()
}
```

- Compile desktop app for Windows 10 to `./build` folder:

```bash
$ xgo -out ./build/spa_desktop \
	-ldflags="-H windowsgui" \
	--targets=windows-10/amd64 \
	github.com/user/spa-desktop-app
```

- Compile desktop app for Linux and macOS to `./build` folder:

```bash
$ xgo -out ./build/spa_desktop \
	--targets=linux/amd64,darwin/amd64 \
	github.com/user/spa-desktop-app
```

> ⚠️ All compiled for 64-bit systems.

<a name="ch-4-1"></a>
### Hint for macOS

How to prepare files for `.app` file, I have already told in [this](https://dev.to/koddr/how-to-create-a-native-macos-app-on-go-golang-and-react-js-with-full-code-protection-part-1-463k) article. For shipping your desktop app to macOS users in _usual_ manner (_drag'n'drop installer_ on `.dmg` format), we can use `node-appdmg`:

{% github LinusU/node-appdmg no-readme %}

I like this **Node.js** library, because it have simple install and understandable configuration. If you have some _design skills_, result may be something like this:

![Yandex.Music Desktop](https://dev-to-uploads.s3.amazonaws.com/i/kluaopf134oqbhbhh8xa.jpg)

<a name="ch-4-2"></a>
### Windows 10 problem

For a visual demonstration problem, I'll use my own **Yandex.Music Desktop**:

{% github koddr/yandex-music-desktop no-readme %}

So, desktop app build this way always running from the _default_ OS webview layer. That means, if you **removed** Edge browser — webview layer will be Internet Explorer 11 and **not** Chrome (FireFox, Opera, etc.), because it's _third-party software_ for Windows! 

> I check it from my test-stand with _Windows 10 Pro x64_ (version 1903, OS build 18362.535). On screenshot below (from left to right):
> 
> _Yandex.Music Desktop app_, _Internet Explorer 11_, _MS Edge 18_ 👇

![Windows 10 main problem](https://dev-to-uploads.s3.amazonaws.com/i/jv6o52ig1tlz56x70ljz.PNG)

#### How to solve this? 

I have no answer to that question... Therefore, the best option is to _warn_, that service will **not work**, if Edge browser is not on the user's system. 

You can set up a message, if catch **User-Agent** like this:

```bash
Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
```

<a name="ch-5"></a>
## What's next?

I advise you to experiment with this knowledge. For example, in the direction of porting your **favorite websites** in native apps as the same way. 👍

<a name="ch-6"></a>
## Questions

- What is happen with app window, when you change `webview.Settings.Resizable` to `false` on your Go app?
- How to disguise a _Windows 10 problem_ by Golang (_hint: use HTTP headers and make redirect to `ie-block.html` page, if IE detected_)?

<a name="ch-7"></a>
## Exercises

- Build your Go app to other OS (and arch), using `XGO` package.
- Solve a _Windows 10 (Internet Explorer) problem_, by catch `UserAgent` by JavaScript or Go (_hint: see above hint_).

<a name></a>
## Photo by

[Title] Med Badr Chemmaoui https://unsplash.com/photos/ZSPBhokqDMc
[1, 2] Somewhere from Google Search 🤷️
[3, 4] Vic Shóstak https://github.com/koddr/yandex-music-desktop

<a name=""></a>
## P.S.

If you want more articles (like this) on this blog, then post a comment below and subscribe to me. Thanks! 😻

And of course, you can help me make developers' lives even better! Just connect to one of my projects as a contributor. It's easy!

My projects that need your help (and stars) 👇

- 🔥 [gowebly][gowebly_url]: A next-generation CLI tool for easily build amazing web applications with Go on the backend, using htmx & hyperscript and the most popular atomic/utility-first CSS frameworks on the frontend.
- ✨ [create-go-app][cgapp_url]: Create a new production-ready project with Go backend, frontend and deploy automation by running one CLI command.
- 🏃 [yatr][yatr_url]: Yet Another Task Runner allows you to organize and automate your routine operations that you normally do in Makefile (or else) for each project.
- 📚 [gosl][gosl_url]: The Go Snippet Library provides snippets collection for working with routine operations in your Go programs with a super user-friendly API and the most efficient performance.
- 🏄‍♂️ [csv2api][csv2api_url]: The parser reads the CSV file with the raw data, filters the records, identifies fields to be changed, and sends a request to update the data to the specified endpoint of your REST API.
- 🚴 [json2csv][json2csv_url]: The parser can read given folder with JSON files, filtering and qualifying input data with intent & stop words dictionaries and save results to CSV files by given chunk size.

<!-- Footer links -->

[gowebly_url]: https://github.com/gowebly
[cgapp_url]: https://github.com/create-go-app
[yatr_url]: https://github.com/koddr/yatr
[gosl_url]: https://github.com/koddr/gosl
[csv2api_url]: https://github.com/koddr/csv2api
[json2csv_url]: https://github.com/koddr/json2csv