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
|
|
|
|
---
|
|
|
|
|
|
|
|
import Tabs from '@theme/Tabs';
|
|
|
|
import TabItem from '@theme/TabItem';
|
|
|
|
|
|
|
|
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-03-19 06:02:55 +00:00
|
|
|
This demo was tested against Wails `v2.4.0` on 2023 March 18 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:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
cd frontend
|
|
|
|
curl -L -o src/assets/logo.png https://sheetjs.com/sketch1024.png
|
|
|
|
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
|
|
|
|
cd ..
|
|
|
|
```
|
|
|
|
|
|
|
|
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!
|