Build cross-platform modern desktop apps in Go + HTML5

Overview

Lorca

Build Status GoDoc Go Report Card

Lorca

A very small library to build modern HTML5 desktop apps in Go. It uses Chrome browser as a UI layer. Unlike Electron it doesn't bundle Chrome into the app package, but rather reuses the one that is already installed. Lorca establishes a connection to the browser window and allows calling Go code from the UI and manipulating UI from Go in a seamless manner.


Features

  • Pure Go library (no cgo) with a very simple API
  • Small application size (normally 5-10MB)
  • Best of both worlds - the whole power of HTML/CSS to make your UI look good, combined with Go performance and ease of development
  • Expose Go functions/methods and call them from JavaScript
  • Call arbitrary JavaScript code from Go
  • Asynchronous flow between UI and main app in both languages (async/await and Goroutines)
  • Supports loading web UI from the local web server or via data URL
  • Supports embedding all assets into a single binary
  • Supports testing your app with the UI in the headless mode
  • Supports multiple app windows
  • Supports packaging and branding (e.g. custom app icons). Packaging for all three OS can be done on a single machine using GOOS and GOARCH variables.

Also, limitations by design:

  • Requires Chrome/Chromium >= 70 to be installed.
  • No control over the Chrome window yet (e.g. you can't remove border, make it transparent, control position or size).
  • No window menu (tray menus and native OS dialogs are still possible via 3rd-party libraries)

If you want to have more control of the browser window - consider using webview library with a similar API, so migration would be smooth.

Example

ui, _ := lorca.New("", "", 480, 320)
defer ui.Close()

// Bind Go function to be available in JS. Go function may be long-running and
// blocking - in JS it's represented with a Promise.
ui.Bind("add", func(a, b int) int { return a + b })

// Call JS function from Go. Functions may be asynchronous, i.e. return promises
n := ui.Eval(`Math.random()`).Float()
fmt.Println(n)

// Call JS that calls Go and so on and so on...
m := ui.Eval(`add(2, 3)`).Int()
fmt.Println(m)

// Wait for the browser window to be closed
<-ui.Done()

Also, see examples for more details about binding functions, embedding assets and packaging binaries.

Hello World

Here are the steps to run the hello world example.

cd examples/counter
go get
go run main.go

How it works

Under the hood Lorca uses Chrome DevTools Protocol to instrument on a Chrome instance. First Lorca tries to locate your installed Chrome, starts a remote debugging instance binding to an ephemeral port and reads from stderr for the actual WebSocket endpoint. Then Lorca opens a new client connection to the WebSocket server, and instruments Chrome by sending JSON messages of Chrome DevTools Protocol methods via WebSocket. JavaScript functions are evaluated in Chrome, while Go functions actually run in Go runtime and returned values are sent to Chrome.

What's in a name?

There is kind of a legend, that before his execution Garcia Lorca have seen a sunrise over the heads of the soldiers and he said "And yet, the sun rises...". Probably it was the beginning of a poem. (J. Brodsky)

Lorca is an anagram of Carlo, a project with a similar goal for Node.js.

License

Code is distributed under MIT license, feel free to use it in your proprietary projects as well.

Issues
  • Application dies after a few seconds

    Application dies after a few seconds

    I compiled both the example and the following program on Linux and Windows. They run fine for a few seconds and then they exit automatically with no errors. Should they not stay running until I close the browser?

    I am using Go version go1.11.2 and Chrome 70.0.3538.102 (Official Build) (64-bit)

    package main

    import ( "fmt" "os"

    "github.com/zserge/lorca"
    

    )

    func main() {

    ui, err := lorca.New("", "", 480, 320)
    
    if err != nil {
    	fmt.Fprintf(os.Stderr, "fatal: %v\n", err)
    	os.Exit(1)
    }
    
    
    defer ui.Close()
    
    // Bind Go function to be available in JS. Go function may be long-running and
    // blocking - in JS it's represented with a Promise.
    ui.Bind("add", func(a, b int) int { return a + b })
    
    // Call JS function from Go. Functions may be asynchronous, i.e. return promises
    n := ui.Eval(`Math.random()`).Float()
    fmt.Println(n)
    
    // Call JS that calls Go and so on and so on...
    m := ui.Eval(`add(2, 3)`).Int()
    fmt.Println(m)
    
    // Wait for the browser window to be closed
    <-ui.Done()
    

    }

    opened by mikeptweet 10
  • Support Chromium based Microsoft Edge

    Support Chromium based Microsoft Edge

    I took the liberty of creating this issue so we can track and centralize discussion around supporting the upcoming Chromium engine based Microsoft Edge.

    Microsoft's official announcement (archive.org copy) (PDF copy) (Gist markdown copy)

    What

    Today we’re announcing that we intend to adopt the Chromium open source project in the development of Microsoft Edge on the desktop to create better web compatibility for our customers and less fragmentation of the web for all web developers.

    When

    Over the next year or so, we’ll be making a technology change that happens “under the hood” for Microsoft Edge, gradually over time, and developed in the open so those of you who are interested can follow along.

    My take

    This is potentially great news for Lorca on Windows if future Edge provides the features that Lorca needs. Current version of Edge on Windows 10 spawns a private Edge session for me when running:

    start shell:AppsFolder\Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge -private https://github.com

    image

    But my understanding is that Lorca also relies on Chrome DevTools Protocol. I hope to see that available in the new Edge.

    opened by ww9 6
  • Running main readme example, gives: ./main.go:68:36: undefined: FS

    Running main readme example, gives: ./main.go:68:36: undefined: FS

    I'm on Ubuntu 20.10: Linux G14 5.10.4-051004-generic #202012301142 SMP Wed Dec 30 11:44:55 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

    > (base) [email protected]:~/Sites/go/lorca$ cd examples/counter
    > (base) [email protected]:~/Sites/go/lorca/examples/counter$ go get
    > go: downloading golang.org/x/net v0.0.0-20200222125558-5a598a2470a0
    > (base) [email protected]:~/Sites/go/lorca/examples/counter$ go run main.go
    > # command-line-arguments
    > ./main.go:68:36: undefined: FS
    

    Any ideas?

    opened by rw3iss 5
  • feat: added RawValue interface

    feat: added RawValue interface

    To allow for the detection of a nil return, a new interface is added (to maintain backwards compatibility) and implemented by value. This interface, RawValue, allows the retrieval of the raw bytes but requires a type assertion.

    Fixes #126

    opened by nrwiersma 5
  • ui.Eval does not return a value

    ui.Eval does not return a value

    Grabbing HTML value from document via Eval returns no value. Not sure if this is a bug or I have bad HTML. I do not get any runtime errors.

    My code

    package main
    
    import (
    	"fmt"
    	"net/url"
    
    	"github.com/zserge/lorca"
    )
    
    var (
    	ui1        lorca.UI
    	HTML_entry string = `
    <html>
        <body>
            <input hidden type="text" name="MYVAR" value="testVal">
            <input type="submit" onclick="golangfunc()"
        </body>
    </html>
    `
    )
    
    func main() {
    	ui1, _ = lorca.New("data:text/html,"+url.PathEscape(HTML_entry), "", 480, 320)
    	ui1.Bind("golangfunc", golangfunc)
    	defer ui1.Close()
    	<-ui1.Done()
    }
    
    func golangfunc() {
    	htmlvar := ui1.Eval(`document.getElementsByName('MYVAR').value`).String()
    	fmt.Println(htmlvar)
    }
    
    opened by cmdpwnd 5
  • Chromium parameters not being passed correctly

    Chromium parameters not being passed correctly

    System information:

    • Arch Linux with kernel 4.19.101-1
    • Go version go1.13.8 linux/amd64

    Steps to reproduce:

    • Create a new go file and paste the example code from https://github.com/zserge/lorca#example
    • Run the file using go run or build and run (it does not seem to make any difference)
    • Get the pid of the running application and take a look to all of it's child processes (this can be done manually using htop with tree view, or by running ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p PID_OF_PARENT))

    Current behavior: There is a whitespace that gets inserted in between parameters, it appears randomly between arguments, for example sometimes it turns --disable-background-networking into --disable-background- etworking or --disable-background-timer-throttling into --disable-ba kground-timer-throttling. The whitespace is not a visual issue as it appears even if redirecting the output to a text file.

    See the whitespace affecting --disable-ba kground-timer-throttling In the example below:

    $ ps --forest -o pid,tty,stat,time,cmd -g $(ps -o sid= -p 67930)
        PID TT       STAT     TIME CMD
      51417 pts/10   Ss   00:00:00 /bin/bash
      67834 pts/10   Sl+  00:00:00  \_ go run hello.go
      67930 pts/10   Sl+  00:00:00      \_ /tmp/go-build688287313/b001/exe/hello
      67936 pts/10   Sl+  00:00:02          \_ /usr/lib/chromium/chromium --disable-background-networking --disable-ba kground-timer-throttling --disable-backgrounding-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-default-apps --disable-dev-shm-usage --disable-infobars --disable-extensions --disable-features=site-per-process --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-sync --disable-translate --metrics-recording-only --no-first-run --safebrowsing-disable-auto-update --enable-automation --password-store=basic --use-mock-keychain --app=data:text/html,<html></html> --user-data-dir=/tmp/lorca366230083 --window-size=480,320 --remote-debugging-port=0
      67939 pts/10   S+   00:00:00              \_ /usr/lib/chromium/chromium --type=zygote --user-data-dir=/tmp/lorca366230083
      67941 pts/10   S+   00:00:00              |   \_ /usr/lib/chromium/chromium --type=zygote --user-data-dir=/tmp/lorca366230083
      67970 pts/10   Sl+  00:00:00              |       \_ /usr/lib/chromium/chromium --type=renderer --disable-background-timer-throttling --disable-breakpad --enable-automation --disable-webrtc-apm-in-audio-service --remote-debugging-port=0 --field-trial-handle=intentionally-hidden --disable-features=site-per-process --lang=en-US --user-data-dir=/tmp/lorca366230083 --disable-client-side-phishing-detection --disable-oor-cors --enable-auto-reload --num-raster-threads=4 --enable-main-frame-before-activation --renderer-client-id=4 --shared-files=v8_snapshot_data:100
      67960 pts/10   Sl+  00:00:00              \_ /usr/lib/chromium/chromium --type=gpu-process --field-trial-handle=intentionally-hidden --disable-features=site-per-process --disable-breakpad --user-data-dir=/tmp/lorca366230083 --gpu-preferences=KAAAAAAAAAAgAAAgAAAAAAAAYAAAAAAAEAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAA --shared-files
      67962 pts/10   Sl+  00:00:00              \_ /usr/lib/chromium/chromium --type=utility --field-trial-handle=intentionally-hidden --disable-features=site-per-process --lang=en-US --service-sandbox-type=network --disable-webrtc-apm-in-audio-service --user-data-dir=/tmp/lorca366230083 --shared-files=v8_snapshot_data:100
    

    Expected behavior: No whitespace gets inserted between parameters

    opened by thejavascriptman 4
  • go version 1.12 not allowed

    go version 1.12 not allowed

    when I use go version 1.12 and 1.12.3 build my exe,I cannot open my exe, when I double click exe nothing to show, then I use go version 1.11.3 window/amd64 build, then it works , I cant find why, hope an cool person to help me, thank you very much

    opened by emisty 3
  • undefined: FS

    undefined: FS

    Getting when running the counter example or anything similar

    # command-line-arguments
    .\main.go:32:36: undefined: FS
    
    ln, err := net.Listen("tcp", "127.0.0.1:0")
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer ln.Close()
    	go http.Serve(ln, http.FileServer(FS)) // FS here is what undefined?
    	ui.Load(fmt.Sprintf("http://%s", ln.Addr()))
    
    opened by Almoullim 3
  • No easy way to terminate whole application

    No easy way to terminate whole application

    I was trying to close my lorca app in two ways:

    1. By binding go function which runs os.Exit(0) and running it in js (actually it was vue, but I think that it doesn't matter)
    2. By running kill <my-app-ID-number>

    Both ways terminated only code written in go, but rest of app (chromium UI layer) was still in its place.

    I observed that after killing my app manually by clicking Ctrl + c in terminal output of ps aux | grep chromium was following: karol 9725 0.0 0.0 6208 888 pts/2 S+ 22:13 0:00 grep chromium, however by killing my app by kill <my-app-ID-number>, output of ps aux | grep chromium was following:

    karol     9494  2.4  1.9 3012884 156584 pts/0  SLl  22:13   0:00 /usr/lib/chromium/chromium --show-component-extension-options --enable-gpu-rasterization --no-default-browser-check --disable-pings --media-router=0 --enable-remote-extensions --load-extension= --disable-background-networking --disable-background-timer-throttling --disable-backgrounding-occluded-windows --disable-breakpad --disable-client-side-phishing-detection --disable-default-apps --disable-dev-shm-usage --disable-infobars --disable-extensions --disable-features=site-per-process --disable-hang-monitor --disable-ipc-flooding-protection --disable-popup-blocking --disable-prompt-on-repost --disable-renderer-backgrounding --disable-sync --disable-translate --metrics-recording-only --no-first-run --safebrowsing-disable-auto-update --enable-automation --password-store=basic --use-mock-keychain --app=data:text/html,<html></html> --user-data-dir=/tmp/lorca025088096 --window-size=720,720 --class=Lorca --remote-debugging-port=0
    karol     9508  0.0  0.0   5740  1772 pts/0    S    22:13   0:00 /usr/lib/chromium/chrome-sandbox /usr/lib/chromium/chromium --type=zygote --user-data-dir=/tmp/lorca025088096
    karol     9509  0.1  0.7 408188 60800 pts/0    SL   22:13   0:00 /usr/lib/chromium/chromium --type=zygote --user-data-dir=/tmp/lorca025088096
    karol     9511  0.0  0.1 408188 14264 pts/0    S    22:13   0:00 /usr/lib/chromium/chromium --type=zygote --user-data-dir=/tmp/lorca025088096
    karol     9534  1.0  1.4 1226304 117532 pts/0  SLl  22:13   0:00 /usr/lib/chromium/chromium --type=gpu-process --field-trial-handle=5158464758563543256,8617488245687844448,131072 --disable-features=site-per-process --disable-breakpad --enable-gpu-rasterization --user-data-dir=/tmp/lorca025088096 --gpu-preferences=KAAAAAAAAACAAAAAAQAAAAAAAAAAAGAAAAAAAAEAAAAIAAAAAAAAAAgAAAAAAAAA --service-request-channel-token=5379940991211926664
    karol     9684  1.1  1.1 1389292 93324 pts/0   Sl   22:13   0:00 /usr/lib/chromium/chromium --type=renderer --disable-background-timer-throttling --disable-breakpad --enable-automation --field-trial-handle=5158464758563543256,8617488245687844448,131072 --disable-features=site-per-process --disable-gpu-compositing --service-pipe-token=921988823902182683 --lang=en-US --user-data-dir=/tmp/lorca025088096 --disable-client-side-phishing-detection --enable-offline-auto-reload --enable-offline-auto-reload-visible-only --num-raster-threads=2 --enable-main-frame-before-activation --service-request-channel-token=921988823902182683 --renderer-client-id=5 --shared-files=v8_context_snapshot_data:100,v8_natives_data:101
    karol     9725  0.0  0.0   6208   888 pts/2    S+   22:13   0:00 grep chromium
    

    So technically go layer is an actual app, but UI layer isn't actually an app, but chromium process(es). Can we "merge" these two layers to one my-app process?

    opened by strang1ato 2
  • Stability question

    Stability question

    I understand Lorca does not ship with as much garbage as Electron because it uses an installed version of Chrome by the user instead of shipping with it's own version. How does it handle a situation where chrome is non-existent on the installed machine or chrome is too old on the installed machine causing some things in my web application to not function right?

    opened by coloredlambda 2
  • Ctrl-t and ctrl-n open new browser window

    Ctrl-t and ctrl-n open new browser window

    On Windows, standard chrome shortcuts ctrl-t and ctrl-n open a new, empty browser window, which is probably not what any application writer wants.

    If possible, they should be blocked. Better yet, it would be good if that was routed through logic in Go program so that user of library can decide if this should be blocked or allowed to proceed. If allowed to proceed, there should be a way to specify which html file or url to load.

    opened by kjk 2
  • Seperate Chromium and Edge UI's

    Seperate Chromium and Edge UI's

    Seperate the chromium and EDGE UI's into lorca.NewChromium and lorca.NewEdge so that the user can choose to use Edge instead of chrome when they have booth installed. Also, do not automatically add in all the default arguments. Instead make these public through AdditionalEdgeArgs and AdditionalChromiumArgs so that the user is not forced to use all the default arguments.

    opened by georgemcarlson 0
  • window.showOpenFilePicker is not a function

    window.showOpenFilePicker is not a function

    opened by edp1096 0
  • Adds support for acting as a Chrome wrapper without the --app flag, passing custom arguments to Chrome, and Brave Browser

    Adds support for acting as a Chrome wrapper without the --app flag, passing custom arguments to Chrome, and Brave Browser

    I would like to use Lorca as a way of pre-configuring Chromium browsers to work in particular environments, in particular as a means of configuring Chromium's to browse the I2P anonymous overlay network. This PR adds support for running Chrome without passing the --app flag and no longer appearing as a "kiosk" type browser. It's also adds the ability to pass custom arguments when operating in this mode. That way I can do things like pass --proxy settings and load unpacked extensions off the filesystem. I'm currently using Lorca in this fashion in the package https://github.com/eyedeekay/aluminumoxynitride which is an I2P wrapping Browser for Chromium.

    I also added support for Brave, a popular Chromium fork with a supposed focus on privacy and emerging web technologies. This was actually partly because it presents a solution the difficulties a visually-impaired user was having getting their Brave Browser configured for I2P. Personally I am not a Brave user, but this user suggested that they preferred the accessibility features of Chrome-based browsers and chose Chrome on that basis. https://old.reddit.com/r/i2p/comments/t9q812/i2p_with_brave_on_mac_os_x/

    opened by eyedeekay 0
  • You should use the devtools protocol and not websockets

    You should use the devtools protocol and not websockets

    Hello my name is Frank Lemanschik i am a german Engineer and i am working on exact the same project but with a other runtime not go based. But i guess my Studies will help you.

    i try to create https://github.com/open-pwa/open-pwa and your welcome to join that effort as it would be great if we would implement also go runners with the same protocol and api.

    Open Pwa is in it's Core about Connections between the Host System and the Browser so like your project.

    Your using Websockets at present to do the Message Exchange while that works it is highly insecure under many situations and is not useable at scale on a single machine like a Desktop PC that whants to install many diffrent apps.

    I Guess your using lorca as foundation "Electron" Replacement

    https://github.com/GoogleChromeLabs/carlo look at this for example that is exactly what you need to implement it uses the process pipe + devtools protocol.

    Some more short details about open-pwa

    It is Designed to get a Platform to Install and Run Apps it offers the Installer and User Interactions that are needed to handle Application Permissions.

    • It will design and work out a Api like the existing PWA one That will turn any Browser and Host Os or even only a Host Os into a Android like OS that kann install applications and give them diffrent permissions and Isolations.
    • open-pwa could be written in go and we could reuse and integrate your code rebranded and we could exchange patches and concepts.
    opened by frank-dspeed 0
  • Running with latest Chrome version

    Running with latest Chrome version

    Latest Chrome version no longer supports the "--disable-infobars" argument, so lorca now runs with the text "Chrome is being controlled by automated test software" in the info-bar. To be fair ...It does not break the running of the program but it is annoying.
    Argument should be replaced by an "enable-automation" Chrome option.

    opened by ReneJBosch 18
Owner
Serge Zaitsev
Turning complex problems into a lightweight and simple software solutions.
Serge Zaitsev
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

ExampleTrayGUI An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functi

Grant Moore 48 Jun 20, 2022
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functional build process. This repository is intended as a quick reference to help others start similar projects using the referenced libraries and will not be actively maintained.

Grant Moore 48 Jun 20, 2022
An example desktop system tray application that can launch HTML5 windows. Go source with a build process for Windows, Mac and Linux.

ExampleTrayGUI An example cross-platform (Mac, Windows, Linux) system tray application that can launch HTML5 windows, developed in Go including functi

Owen Moore 48 Jun 20, 2022
Build cross platform GUI apps with GO and HTML/JS/CSS (powered by Electron)

Thanks to go-astilectron build cross platform GUI apps with GO and HTML/JS/CSS. It is the official GO bindings of astilectron and is powered by Electr

Quentin Renard 4.4k Jun 23, 2022
Build cross platform GUI apps with GO and HTML/JS/CSS (powered by nwjs)

gowd Build cross platform GUI apps with GO and HTML/JS/CSS (powered by nwjs) How to use this library: Download and install nwjs Install this library g

Danny 361 Jun 22, 2022
Kita is a declarative, reactive GUI toolkit for build cross platform apps with web technology with single codebase

Kita is a declarative, reactive GUI toolkit for build cross platform apps with web technology with single codebase. Inspired by Flutter, React. S

zhuah 106 Apr 18, 2022
UIKit - A declarative, reactive GUI toolkit for build cross platform apps with web technology with single codebase

UIKit - A declarative, reactive GUI toolkit for build cross platform apps with web technology with single codebase

zhuah 106 Apr 18, 2022
Create desktop apps using Go and Web Technologies.

Build desktop applications using Go & Web Technologies. The traditional method of providing web interfaces to Go programs is via a built-in web server

Wails 7.7k Jun 26, 2022
A package to build progressive web apps with Go programming language and WebAssembly.

go-app is a package to build progressive web apps (PWA) with Go programming language and WebAssembly. It uses a declarative syntax that allows creatin

Maxence Charriere 6.2k Jun 29, 2022
gosx-notifier is a Go framework for sending desktop notifications to OSX 10.8 or higher

gosx-notifier A Go lib for sending desktop notifications to OSX Mountain Lion's (10.8 or higher REQUIRED) Notification Center. Update 4/3/2014 On OSX

Ralph Caraveo III 571 Jun 2, 2022
A Go (golang) Custom Flutter Engine Embedder for desktop

Go Flutter desktop embedder ⚠️ Warning: this project has been moved to its own organization. Please take a look at its new location: github.com/go-flu

Pierre Champion | Drakirus 95 May 19, 2022
A full desktop environment for Linux/Unix using Fyne

About FyneDesk is an easy to use Linux/Unix desktop environment following material design. It is build using the Fyne toolkit and is designed to be ea

Fyne.io 485 Jun 21, 2022
A unified graphical user experience toolkit for Go desktop applications

Unison A unified graphical user experience toolkit for Go desktop applications. macOS, Windows, and Linux are supported. Required setup Unison is buil

Richard Wilkes 14 Jun 17, 2022
Example Go desktop app using HTML

webview-example This repo contains an example/starter for building a webview app

Jessie 4 Jun 14, 2022
Ps4gdb desktop - PS4GDB consists of two components

PS4GDB PS4GDB consists of two components. The first component is the gdbstub run

Mr. Nobody 17 Jun 21, 2022
Cross platform GUI in Go based on Material Design

About Fyne is an easy to use UI toolkit and app API written in Go. It is designed to build applications that run on desktop and mobile devices with a

Fyne.io 17.5k Jun 24, 2022
An experimental Go cross platform UI library.

GXUI - A Go cross platform UI library. Notice: Unfortunately due to a shortage of hours in a day, GXUI is no longer maintained. If you're looking for

Google 4.5k Jun 21, 2022
Tiny cross-platform webview library for C/C++/Golang. Uses WebKit (Gtk/Cocoa) and Edge (Windows)

webview A tiny cross-platform webview library for C/C++/Golang to build modern cross-platform GUIs. Also, there are Rust bindings, Python bindings, Ni

webview 10.2k Jun 24, 2022
RobotGo, Go Native cross-platform GUI automation @vcaesar

Robotgo Golang Desktop Automation. Control the mouse, keyboard, bitmap, read the screen, Window Handle and global event listener. RobotGo supports Mac

vgo 7.6k Jun 23, 2022