Create a JavaScript single-page application (SPA) in a WebView
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:
- Provides interfaces to bridge communication between JavaScript senders and Go app receivers.
- Embeds all fonts, images, sounds, etc.. as Base64 encoded strings to be used in CSS/JavaScript includes.
- Transpiles SPA sources to a single file bundle which is front-loaded on Go application initialization using
data:
- 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.
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
Transpile the SPA, compile the Go application, and run the example in one command:
$ make
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.
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
Once compiled it should be as easy as..
$ webview-app
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)
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 |
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');
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])
})
...
}
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`);
}
It should, as long as the following requirements are met:
- The application uses TypeScript, Jest, and Webpack. See
tsconfig
andwebpack.config
for build details. - Assets are encoded as Base64 data URI and embed in its corresponding import (e.g. Script, Style Sheet, HTML)
- Webpack writes application output to a single bundle file
/dist/main.bundle.js
which is parsed by Go. - The webview JavaScript libraries and related tests exist in their current respective locations.
- webview_go - Go language binding for the webview library.
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).
This package is maintained under the Semantic Versioning guidelines.
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