forked from sheetjs/docs.sheetjs.com
		
	
		
			
	
	
		
			222 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			222 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|  | --- | ||
|  | title: Wails | ||
|  | pagination_prev: demos/mobile | ||
|  | pagination_next: demos/grid | ||
|  | 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. | ||
|  | 
 | ||
|  | This demo was tested against Wails `v2.0.0-beta.44.2` on 2022 August 31 using | ||
|  | the Svelte TypeScript starter. | ||
|  | 
 | ||
|  | :::caution | ||
|  | 
 | ||
|  | Wails currently does not provide the equivalent of NodeJS `fs` module. | ||
|  | 
 | ||
|  | The HTML File Input Element does not show a file picker.  This is a known bug. | ||
|  | 
 | ||
|  | All raw file operations must be performed in Go code. | ||
|  | 
 | ||
|  | ::: | ||
|  | 
 | ||
|  | 
 | ||
|  | The "Complete Example" creates an app that looks like the screenshot: | ||
|  | 
 | ||
|  |  | ||
|  | 
 | ||
|  | <details><summary><b>Complete Example</b> (click to show)</summary> | ||
|  | 
 | ||
|  | 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` | ||
|  | 
 | ||
|  | 5) Build the app with | ||
|  | 
 | ||
|  | ```bash | ||
|  | wails build | ||
|  | ``` | ||
|  | 
 | ||
|  | At the end, it will print the path to the generated program. Run the program! | ||
|  | 
 | ||
|  | </details> | ||
|  | 
 | ||
|  | All operations must be run from Go code.  This example passes Base64 strings. | ||
|  | 
 | ||
|  | ### Reading Files
 | ||
|  | 
 | ||
|  | The file picker and reading operations can be combined in one Go function. | ||
|  | 
 | ||
|  | #### 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
 | ||
|  | 
 | ||
|  | Wails will automatically create `window.go.main.App.ReadFile` for use in JS: | ||
|  | 
 | ||
|  | ```js title="frontend/src/App.svelte" | ||
|  | import { read, utils } from 'xlsx'; | ||
|  | 
 | ||
|  | async function importFile(evt) { | ||
|  | // highlight-start | ||
|  |   const b64 = window['go']['main']['App']['ReadFile'](); | ||
|  |   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 | ||
|  | 
 | ||
|  | ##### Go
 | ||
|  | 
 | ||
|  | Two Go functions will be exposed. | ||
|  | 
 | ||
|  | - `SaveFile` will show the file picker and return the path: | ||
|  | 
 | ||
|  | ```go | ||
|  | import ( | ||
|  |   "context" | ||
|  | // highlight-start | ||
|  |   "github.com/wailsapp/wails/v2/pkg/runtime" | ||
|  | // highlight-end | ||
|  | ) | ||
|  | 
 | ||
|  | 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'; | ||
|  | 
 | ||
|  | 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 */ | ||
|  |   const path = await window['go']['main']['App']['SaveFile'](); | ||
|  | 
 | ||
|  |   /* generate base64 string based on the path */ | ||
|  |   const b64 = write(wb, { bookType: path.slice(path.lastIndexOf(".")+1), type: "base64" }); | ||
|  | 
 | ||
|  |   /* write to file */ | ||
|  |   await window['go']['main']['App']['WriteFile'](b64, path); | ||
|  |   // The demo shows a success message at this point | ||
|  | } | ||
|  | ``` |