/go-webview-app-builder

:window: Create a JavaScript single-page application (SPA) in a WebView

Primary LanguageGoMIT LicenseMIT

WebView App Builder

Create a JavaScript single-page application (SPA) in a WebView

Preview

The Problem

Due to browser Cross-origin resource sharing (CORS) restrictions WebView application sources and related data must be served from a privileged authority that defines a properly configured Access-Control-Allow-Origin header. In an embedded source application, where HTTP sources are served locally, the WebView uses an unprivileged authority about:blank that results with errors when using Fetch, Storage, or Cookie Store APIs.

This package does the following to workaround this:

  1. Provides interfaces to bridge communication between JavaScript senders and Go app receivers.
  2. Embeds all fonts, images, sounds, etc.. as Base64 encoded strings to be used in CSS/JavaScript includes.
  3. Transpiles SPA sources to a single file bundle which is front-loaded on Go application initialization using data:
  4. Compiles Go application and packages SPA sources into a small, self contained binary.

This creates a fast loading, dynamically-driven, desktop application running your favorite SPA framework.

Dependencies

Debian/Ubuntu

The following dependencies are required in order to build for Debian-based operating systems. For alternate OS's (e.g. BSD, Windows) refer to the webview preqequisites install instructions.

$ apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev

Quick and Easy

Transpile the SPA, compile the Go application, and run the example in one command:

$ make

Build from source

Install the new build using gmake.

$ make install

Cross-compile to support Windows, OSX, etc ..

$ make build-<darwin|linux|windows>

Note: Using --debug will enable WebView browser Developer Tools and development mode in the JavaScript application.

Building the JavaScript app

Install the Node.js application dependencies using NPM:

$ make webview-app-install

Transpile ES2017 sources (using TypeScript) and minify to a distribution:

$ make webview-app-build

Running the application

Once compiled it should be as easy as..

$ webview-app

Go application structure

app                              // SPA sources (Aurelia 2 framework example)
app/examples/aurelia/index.tmpl  // File to be imported into the WebView (via webview_go)
app/examples/aurelia/src/webview // JS libraries (Go app bindings, e.g. senders)
lib                              // Go package dependencies.
app.go                           // main (Go app bindings, e.g receivers)

Supported app bindings

The following window functions are accessible when the app is executed in a Go context. When run using NPM the functions fallback to local equivalents, if supported.

Name Description Fallback
browser_AppVersion Returns the Go application defined version. N/A
browser_HttpGet Make HTTP GET request to a remote source. Fetch API
browser_HttpHead Make HTTP HEAD request to a remote source. Fetch API
browser_HttpPost Make HTTP POST request to a remote source. Fetch API
browser_Navigate Store data that references current screen. N/A
browser_OpenExtBrowser Opens URL in an external web browser. N/A
browser_StorageDelete Removes stored item from in-memory cache. Storage API
browser_StorageSet Add data to be stored in-memory cache. Storage API
browser_StorageGet Returns data from in-memory cache. Storage API
browser_Terminate Close the WebView (terminate session). N/A

Usage

The following illustrates the most typical use case.

import {AppRequest} from './webview/http';
import {AppStorage} from './webview/storage';

// Fetch remote resource..
const appReq = new AppRequest();
const result = await appReq.get('https://domain.com/api');
const {Status, Headers, Body} = result;

// parse result, cache locally.
const value = JSON.parse(Body).uuid;

await AppStorage.set('api-uuid', value);

// .. and later in code
const uuid = AppStorage.get('api-uuid');

Adding custom bindings

Go app receiver example

import "github.com/nuxy/go-webview-app-builder/lib"

// Browser settings (defaults).
var settings = lib.BrowserSettings{
    Title:  "WebView App",
    Height: 768,
    Width:  1024,
    Resize: true,
    Debug:  false,
}

func main() {
    browser := lib.NewBrowser('<html></html>', settings)

    // Concatenate string arguments and return result to JavaScript sender.
    browser.BindFuncReturn("browser_ConcatStrings", func(arg ...string) string {
        return arg[0] + arg[1] + arg[2]
    })

    // Pass arguments to Go function. Returns nothing to JavaScript sender.
    browser.BindFuncVoid("browser_ProcessString", func(arg ...string) {
        myCustomFunction(arg[0])
    })

    ...
}

JavaScript sender example

import {webViewBindExists} from './webview/utils';

// Concatenate string arguments.
async function concatStrings(v1, v2, v3) {
  const bindingName = 'browser_ConcatStrings';

  if (webViewBindExists(bindingName)) {
    return await window[bindingName](v1, v2, v3);
  }

  throw new Error(`Go receiver "${bindingName}" doesn't exist`);
}

// Process the string argument.
async function executeAndVoid(v) {
  const bindingName = 'browser_ProcessString';

  if (webViewBindExists(bindingName)) {
    return await window[bindingName](v);
  }

  throw new Error(`Go receiver "${bindingName}" doesn't exist`);
}

Does this support other JavaScript frameworks?

It should, as long as the following requirements are met:

  1. The application uses TypeScript, Jest, and Webpack. See tsconfig and webpack.config for build details.
  2. Assets are encoded as Base64 data URI and embed in its corresponding import (e.g. Script, Style Sheet, HTML)
  3. Webpack writes application output to a single bundle file /dist/main.bundle.js which is parsed by Go.
  4. The webview JavaScript libraries and related tests exist in their current respective locations.

References

  • webview_go - Go language binding for the webview library.

Contributions

If you fix a bug, or have a code you want to contribute, please send a pull-request with your changes. (Note: Before committing your code please ensure that you run golint and gofmt on contributed files).

Versioning

This package is maintained under the Semantic Versioning guidelines.

License and Warranty

This package is distributed in the hope that it will be useful, but without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose.

go-webview-app-builder is provided under the terms of the MIT license

Author

Marc S. Brooks