--- title: Sheets in Golang with Goja sidebar_label: Go + Goja pagination_prev: demos/bigdata/index pagination_next: solutions/input --- import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; Goja[^1] is a pure Go implementation of ECMAScript 5. [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing data from spreadsheets. This demo uses Goja and SheetJS to read and write spreadsheets. We'll explore how to load SheetJS in the Goja engine, exchange binary data with a Go program and process spreadsheets and structured data. The ["Complete Example"](#complete-example) section makes a command-line tool for reading arbitrary workbooks and writing data to XLSB workbooks. ## Integration Details The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone) can be parsed and evaluated in a Goja context. ### Initialize Goja Goja does not provide a `global` variable. It can be created in one line: ```go /* initialize */ vm := goja.New() /* goja does not expose a standard "global" by default */ // highlight-next-line v, err := vm.RunString("var global = (function(){ return this; }).call(null);") ``` ### Load SheetJS Scripts The shim and main libraries can be loaded by reading the scripts from the file system and evaluating in the Goja context: ```go func safe_run_file(vm *goja.Runtime, file string) { data, err := ioutil.ReadFile(file) if err != nil { panic(err) } src := string(data) _, err = vm.RunString(src) if err != nil { panic(err) } } // ... safe_run_file(vm, "shim.min.js") safe_run_file(vm, "xlsx.full.min.js") ``` To confirm the library is loaded, `XLSX.version` can be inspected: ```go /* get version string */ v, err := vm.RunString("XLSX.version") fmt.Printf("SheetJS library version %s\n", v) ``` ### Reading Files Files can be read into `[]byte`: ```go /* read file */ data, _ := ioutil.ReadFile("sheetjs.xlsx") ``` `[]byte` should be converted to an `ArrayBuffer` from Go: ```go /* load into engine */ vm.Set("buf", vm.ToValue(vm.NewArrayBuffer(data))) /* parse */ wb, _ = vm.RunString("wb = XLSX.read(buf, {type:'buffer'});") ``` ### Writing Files `"base64"` strings can be passed from the JS context to Go code: ```go /* write to Base64 string */ b64str, _ := vm.RunString("XLSX.write(wb, {type:'base64', bookType:'xlsx'})") /* pull data back into Go and write to file */ buf, _ := base64.StdEncoding.DecodeString(b64str.String()) _ = ioutil.WriteFile("sheetjs.xlsx", buf, 0644) ``` ## Complete Example :::note Tested Deployments This demo was tested in the following deployments: | Architecture | Git Commit | Go version | Date | |:-------------|:-----------|:-----------|:-----------| | `darwin-x64` | `79f3a7e` | `1.23.3` | 2024-12-17 | | `darwin-arm` | `ccbae20` | `1.22.3` | 2024-05-23 | | `win11-x64` | `79f3a7e` | `1.23.4` | 2024-12-20 | | `win11-arm` | `ccbae20` | `1.22.3` | 2024-05-25 | | `linux-x64` | `e401ed4` | `1.22.1` | 2024-03-21 | | `linux-arm` | `ccbae20` | `1.19.8` | 2024-05-25 | At the time of writing, Goja did not have proper version numbers. Versions are identified by Git commit hashes. ::: 0) Create a module and install dependencies: ```bash mkdir SheetGoja cd SheetGoja go mod init SheetGoja go get github.com/dop251/goja ``` 1) Download the SheetJS Standalone script, shim script and test file. Move all three files to the project directory: