neyuki 0.6.1

A small Lua-like scripting language implemented in Rust
# @neyuki/webview


Web pages inside a window, rendered by the operating system's web engine: WebView2 on Windows, WKWebView on macOS and WebKitGTK on Linux. Pages can come from a URL, an HTML string or a directory of app files, and the page and the script talk through messages.

A view lives in the same event loop as [@neyuki/ui](ui.md): `ui.run` and `ui.poll` pump it, keep running while a view is open and deliver its events, which are tables with `kind = "webview"`:

- `message`: `data`, the string the page passed to `window.neyuki.postMessage`
- `navigate`: `url`, the page is about to go there
- `load`: `url`, the page finished loading
- `title`: `title`
- `close`: the window's close button was used (`ui.run` honours it unless `autoClose` is false)

Every event also carries `webview`, the view it came from. Everything a page sends is untrusted input: `data` is a string to parse defensively. Pages cannot reach files or processes; the only file access is the optional asset directory, served read-only.

The module is behind the `webview` cargo feature, on by default. On Linux it needs `libwebkit2gtk-4.1` and GTK 3 to build and run; build with `--no-default-features` to leave it out, in which case `isAvailable` returns `false` and `open` raises an error. On Windows the WebView2 Evergreen Runtime is required (preinstalled on Windows 11).

```lua
local webview = require("@neyuki/webview")
local ui = require("@neyuki/ui")

local view = webview.open({
    title = "Hello",
    html = "<button onclick=\"window.neyuki.postMessage('hi')\">Say hi</button>",
})
ui.run(function(events)
    for _, event in events do
        if event.kind == "webview" and event.type == "message" then
            print("page said", event.data)
            view:send({ reply = true })
        end
    end
end)
```

## webview.isAvailable(): boolean


Whether a view can be created here: a display and the system web engine.

## webview.open(options: table?): WebView


Opens a window showing a page. `options` may hold:

- `title`, `width`, `height`, `resizable`, `visible`: as for `ui.open`
- `url` or `html`: the first page
- `devtools`: allow the inspector (default `false`)
- `userAgent`: replace the user agent string
- `initScript`: JavaScript that runs before the page's own scripts on every document
- `autoplay`: media may play without a user gesture (default `false`)
- `backgroundThrottling`: set to `false` to keep timers and audio running while hidden (Windows)
- `dataDir`: a directory for a persistent profile, so cookies and storage survive restarts
- `assets`: `{ dir, scheme? }` serves the files under `dir` (cannot escape it) at `webview.assetUrl(scheme, path)`; `scheme` defaults to `"app"`

Pages get `window.neyuki.postMessage(string)` to send messages to the script.

## webview.assetUrl(scheme: string?, path: string?): string


The address of `path` in an asset directory served under `scheme` (default `"app"`). It is `http://app.localhost/...` on Windows and `app://localhost/...` elsewhere, so build it with this function.

## view:navigate(url: string): ()


Loads `url`.

## view:loadHtml(html: string): ()


Replaces the page with `html`.

## view:reload(): ()


Reloads the page.

## view:eval(js: string): ()


Runs JavaScript in the page without waiting. A result comes back by having the script call `window.neyuki.postMessage`.

## view:send(value: any): ()


Sends `value` to the page: a `neyuki` event is fired on `window`, and `event.detail` holds the value as JSON text.

## view:url(): string


The address the page is at.

## view:setTitle(title: string): ()


Sets the window title.

## view:size(): (number, number)


The logical width and height of the window.

## view:setSize(width: number, height: number): ()


Resizes the window.

## view:show(): ()


Shows the window.

## view:hide(): ()


Hides the window. The page keeps running.

## view:clearData(): ()


Forgets cookies, storage and caches (signs the user out).

## view:assetUrl(path: string?): string


`webview.assetUrl` for the scheme this view was opened with.

## view:isOpen(): boolean


Whether the view has not been closed.

## view:close(): ()


Closes the window and the view. Closing twice is fine.