docs.sheetjs.com/docz/docs/03-demos/06-desktop/03-wails.md

283 lines
6.3 KiB
Markdown
Raw Normal View History

2023-01-05 03:57:48 +00:00
---
title: Wails
2023-01-05 23:33:49 +00:00
pagination_prev: demos/mobile/index
2023-02-28 11:40:44 +00:00
pagination_next: demos/data/index
2023-01-05 03:57:48 +00:00
sidebar_position: 3
sidebar_custom_props:
summary: Webview + Go Backend
---
2023-04-27 09:12:19 +00:00
import current from '/version.js';
2023-01-05 03:57:48 +00:00
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
2023-04-30 12:27:09 +00:00
import CodeBlock from '@theme/CodeBlock';
2023-01-05 03:57:48 +00:00
The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
from JavaScript code.
The "Complete Example" creates an app that looks like the screenshot:
2023-01-09 05:08:30 +00:00
<table><thead><tr>
2023-03-19 06:02:55 +00:00
<th><a href="#complete-example">Win10</a></th>
2023-01-09 05:08:30 +00:00
<th><a href="#complete-example">macOS</a></th>
<th><a href="#complete-example">Linux</a></th>
</tr></thead><tbody><tr><td>
2023-01-05 03:57:48 +00:00
2023-03-19 06:02:55 +00:00
![Win10 screenshot](pathname:///wails/win10.png)
</td><td>
2023-01-09 05:08:30 +00:00
![macOS screenshot](pathname:///wails/macos.png)
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
</td><td>
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
![Linux screenshot](pathname:///wails/linux.png)
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
</td></tr></tbody></table>
2023-01-05 03:57:48 +00:00
2023-02-12 08:15:17 +00:00
## Integration Details
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
All operations must be run from Go code. This example passes Base64 strings.
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
:::caution
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
Wails currently does not provide the equivalent of NodeJS `fs` module. All raw
file operations must be performed in Go code.
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
The HTML File Input Element does not show a file picker. This is a known bug.
The demo works around the issue by showing pickers in Go code.
2023-01-05 03:57:48 +00:00
2023-01-09 05:08:30 +00:00
:::
2023-01-05 03:57:48 +00:00
### Reading Files
The file picker and reading operations can be combined in one Go function.
2023-01-09 05:08:30 +00:00
```mermaid
sequenceDiagram
autonumber
actor User
participant JS
participant Go
User->>JS: click button
JS->>Go: ask for data
Note over Go: Show Open Dialog
Note over Go: Read File Bytes
Note over Go: Generate Base64
Go->>JS: return data
Note over JS: Parse data
Note over JS: Display Table
JS->>User: app shows data
```
2023-01-05 03:57:48 +00:00
#### Go
```go
import (
"context"
// highlight-start
"encoding/base64"
"io/ioutil"
"github.com/wailsapp/wails/v2/pkg/runtime"
// highlight-end
)
type App struct {
ctx context.Context
}
// ReadFile shows an open file dialog and returns the data as Base64 string
func (a *App) ReadFile() string {
// highlight-next-line
selection, err := runtime.OpenFileDialog(a.ctx, runtime.OpenDialogOptions{
Title: "Select File",
Filters: []runtime.FileFilter{
{ DisplayName: "Excel Workbooks (*.xlsx)", Pattern: "*.xlsx", },
// ... more filters for more file types
},
})
if err != nil { return "" } // The demo app shows an error message
// highlight-next-line
data, err := ioutil.ReadFile(selection)
if err != nil { return "" } // The demo app shows an error message
// highlight-next-line
return base64.StdEncoding.EncodeToString(data)
}
```
#### JS
2023-01-09 05:08:30 +00:00
Wails will automatically create bindings for use in JS:
2023-01-05 03:57:48 +00:00
```js title="frontend/src/App.svelte"
import { read, utils } from 'xlsx';
2023-01-09 05:08:30 +00:00
import { ReadFile } from '../wailsjs/go/main/App';
2023-01-05 03:57:48 +00:00
async function importFile(evt) {
// highlight-start
2023-01-09 05:08:30 +00:00
const b64 = await ReadFile();
2023-01-05 03:57:48 +00:00
const wb = read(b64, { type: "base64" });
// highlight-end
const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet
html = utils.sheet_to_html(ws); // generate HTML and update state
}
```
### Writing Files
There is a multi-part dance since the library needs the file extension.
1) Show the save file picker in Go, pass back to JS
2) Generate the file data in JS, pass the data back to Go
3) Write to file in Go
2023-01-09 05:08:30 +00:00
```mermaid
sequenceDiagram
autonumber
actor User
participant JS
participant Go
User->>JS: click button
JS->>Go: ask for path
Note over Go: Show Save Dialog
Go->>JS: path to save file
Note over JS: write workbook
JS->>Go: base64-encoded bytes
Note over Go: decode data
Note over Go: write to file
Go->>JS: write finished
JS->>User: alert
```
2023-01-05 03:57:48 +00:00
##### Go
Two Go functions will be exposed.
- `SaveFile` will show the file picker and return the path:
```go
import (
"context"
2023-01-09 05:08:30 +00:00
// highlight-next-line
2023-01-05 03:57:48 +00:00
"github.com/wailsapp/wails/v2/pkg/runtime"
)
type App struct {
ctx context.Context
}
func (a *App) SaveFile() string {
// highlight-next-line
selection, err := runtime.SaveFileDialog(a.ctx, runtime.SaveDialogOptions{
Title: "Select File",
DefaultFilename: "SheetJSWails.xlsx",
Filters: []runtime.FileFilter{
{ DisplayName: "Excel Workbooks (*.xlsx)", Pattern: "*.xlsx", },
// ... more filters for more file types
},
})
if err != nil { return "" } // The demo app shows an error message
return selection
}
```
- `WriteFile` performs the file write given a Base64 string and file path:
```go
import (
"context"
// highlight-start
"encoding/base64"
"io/ioutil"
// highlight-end
)
type App struct {
ctx context.Context
}
func (a *App) WriteFile(b64 string, path string) {
// highlight-start
buf, _ := base64.StdEncoding.DecodeString(b64);
_ = ioutil.WriteFile(path, buf, 0644);
// highlight-end
}
```
#### JS
Wails will automatically create bindings for use in JS:
```js
import { utils, write } from 'xlsx';
2023-01-09 05:08:30 +00:00
import { SaveFile, WriteFile } from '../wailsjs/go/main/App';
2023-01-05 03:57:48 +00:00
async function exportFile(wb) {
/* generate workbook */
const elt = tbl.getElementsByTagName("TABLE")[0];
const wb = utils.table_to_book(elt);
/* show save picker and get path */
2023-01-09 05:08:30 +00:00
const path = await SaveFile();
2023-01-05 03:57:48 +00:00
/* generate base64 string based on the path */
const b64 = write(wb, { bookType: path.slice(path.lastIndexOf(".")+1), type: "base64" });
/* write to file */
2023-01-09 05:08:30 +00:00
await WriteFile(b64, path);
2023-01-05 03:57:48 +00:00
}
```
2023-01-09 05:08:30 +00:00
## Complete Example
2023-02-12 08:15:17 +00:00
:::note
2023-04-30 12:27:09 +00:00
This demo was tested against Wails `v2.4.1` on 2023 April 30 using
2023-01-09 05:08:30 +00:00
the Svelte TypeScript starter.
2023-02-12 08:15:17 +00:00
:::
2023-01-09 05:08:30 +00:00
0) [Read Wails "Getting Started" guide and install dependencies.](https://wails.io/docs/gettingstarted/installation)
1) Create a new Wails app:
```bash
wails init -n sheetjs-wails -t svelte-ts
```
2) Enter the directory:
```bash
cd sheetjs-wails
```
3) Install front-end dependencies:
2023-04-30 12:27:09 +00:00
<CodeBlock language="bash">{`\
2023-01-09 05:08:30 +00:00
cd frontend
curl -L -o src/assets/logo.png https://sheetjs.com/sketch1024.png
2023-04-30 12:27:09 +00:00
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
cd ..`}
</CodeBlock>
2023-01-09 05:08:30 +00:00
4) Download source files:
- Download [`app.go`](pathname:///wails/app.go) and replace `app.go`
- Download [`App.svelte`](pathname:///wails/App.svelte) and replace
`frontend/src/App.svelte`
```bash
curl -L -o app.go https://docs.sheetjs.com/wails/app.go
curl -L -o frontend/src/App.svelte https://docs.sheetjs.com/wails/App.svelte
```
5) Build the app with
```bash
wails build
```
At the end, it will print the path to the generated program. Run the program!