2023-01-05 03:57:48 +00:00
|
|
|
---
|
|
|
|
title: Electron
|
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: 1
|
|
|
|
sidebar_custom_props:
|
|
|
|
summary: Embedded NodeJS + Chromium
|
|
|
|
---
|
|
|
|
|
|
|
|
import Tabs from '@theme/Tabs';
|
|
|
|
import TabItem from '@theme/TabItem';
|
|
|
|
|
|
|
|
The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported
|
|
|
|
from the main or the renderer thread.
|
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
The "Complete Example" creates an app that looks like the screenshots below:
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
<table><thead><tr>
|
2023-02-21 01:04:05 +00:00
|
|
|
<th><a href="#complete-example">Win10</a></th>
|
2023-02-09 08:33:59 +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-02-21 01:04:05 +00:00
|
|
|
![Win10 screenshot](pathname:///electron/ew.png)
|
|
|
|
|
|
|
|
</td><td>
|
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
![macOS screenshot](pathname:///electron/em.png)
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
</td><td>
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
![Linux screenshot](pathname:///electron/el.png)
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
</td></tr></tbody></table>
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
## Integration Details
|
2023-01-05 03:57:48 +00:00
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
Electron presents a `fs` module. The `require('xlsx')` call loads the CommonJS
|
|
|
|
module, so `XLSX.readFile` and `XLSX.writeFile` work in the renderer thread.
|
2023-01-05 03:57:48 +00:00
|
|
|
|
|
|
|
### Reading Files
|
|
|
|
|
|
|
|
Electron offers 3 different ways to read files, two of which use Web APIs.
|
|
|
|
|
|
|
|
**File Input Element**
|
|
|
|
|
|
|
|
File input elements automatically map to standard Web APIs.
|
|
|
|
|
|
|
|
For example, assuming a file input element on the page:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<input type="file" name="xlfile" id="xlf" />
|
|
|
|
```
|
|
|
|
|
|
|
|
The event handler would process the event as if it were a web event:
|
|
|
|
|
|
|
|
```js
|
|
|
|
async function handleFile(e) {
|
|
|
|
const file = e.target.files[0];
|
|
|
|
const data = await file.arrayBuffer();
|
|
|
|
/* data is an ArrayBuffer */
|
|
|
|
const workbook = XLSX.read(data);
|
|
|
|
|
|
|
|
/* DO SOMETHING WITH workbook HERE */
|
|
|
|
}
|
|
|
|
document.getElementById("xlf").addEventListener("change", handleFile, false);
|
|
|
|
```
|
|
|
|
|
|
|
|
**Drag and Drop**
|
|
|
|
|
|
|
|
The [drag and drop snippet](/docs/solutions/input#example-user-submissions)
|
|
|
|
applies to DIV elements on the page.
|
|
|
|
|
|
|
|
For example, assuming a DIV on the page:
|
|
|
|
|
|
|
|
```html
|
|
|
|
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
|
|
|
|
```
|
|
|
|
|
|
|
|
The event handler would process the event as if it were a web event:
|
|
|
|
|
|
|
|
```js
|
|
|
|
async function handleDrop(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
|
|
const file = e.dataTransfer.files[0];
|
|
|
|
const data = await file.arrayBuffer();
|
|
|
|
/* data is an ArrayBuffer */
|
|
|
|
const workbook = XLSX.read(data);
|
|
|
|
|
|
|
|
/* DO SOMETHING WITH workbook HERE */
|
|
|
|
}
|
|
|
|
document.getElementById("drop").addEventListener("drop", handleDrop, false);
|
|
|
|
```
|
|
|
|
|
|
|
|
**Electron API**
|
|
|
|
|
|
|
|
[`XLSX.readFile`](/docs/api/parse-options) reads workbooks from the file system.
|
|
|
|
`showOpenDialog` shows a Save As dialog and returns the selected file name.
|
|
|
|
Unlike the Web APIs, the `showOpenDialog` flow can be initiated by app code:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* from the renderer thread */
|
|
|
|
const electron = require('@electron/remote');
|
|
|
|
|
|
|
|
/* this function will show the open dialog and try to parse the workbook */
|
|
|
|
async function importFile() {
|
|
|
|
/* show Save As dialog */
|
|
|
|
const result = await electron.dialog.showOpenDialog({
|
|
|
|
title: 'Select a file',
|
|
|
|
filters: [{
|
|
|
|
name: "Spreadsheets",
|
|
|
|
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
/* result.filePaths is an array of selected files */
|
|
|
|
if(result.filePaths.length == 0) throw new Error("No file was selected!");
|
|
|
|
// highlight-next-line
|
|
|
|
return XLSX.readFile(result.filePaths[0]);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-09-24 03:59:48 +00:00
|
|
|
:::note pass
|
2023-01-05 03:57:48 +00:00
|
|
|
|
|
|
|
In older versions of Electron, `showOpenDialog` returned the path directly:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var dialog = require('electron').remote.dialog;
|
|
|
|
|
|
|
|
function importFile(workbook) {
|
|
|
|
var result = dialog.showOpenDialog({ properties: ['openFile'] });
|
|
|
|
return XLSX.readFile(result[0]);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-02-12 08:15:17 +00:00
|
|
|
### Writing Files
|
|
|
|
|
|
|
|
[`XLSX.writeFile`](/docs/api/write-options) writes workbooks to the file system.
|
|
|
|
`showSaveDialog` shows a Save As dialog and returns the selected file name:
|
|
|
|
|
|
|
|
```js
|
|
|
|
/* from the renderer thread */
|
|
|
|
const electron = require('@electron/remote');
|
|
|
|
|
|
|
|
/* this function will show the save dialog and try to write the workbook */
|
|
|
|
async function exportFile(workbook) {
|
|
|
|
/* show Save As dialog */
|
|
|
|
const result = await electron.dialog.showSaveDialog({
|
|
|
|
title: 'Save file as',
|
|
|
|
filters: [{
|
|
|
|
name: "Spreadsheets",
|
|
|
|
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
|
|
|
|
}]
|
|
|
|
});
|
|
|
|
/* write file */
|
|
|
|
// highlight-next-line
|
|
|
|
XLSX.writeFile(workbook, result.filePath);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2023-09-24 03:59:48 +00:00
|
|
|
:::note pass
|
2023-02-12 08:15:17 +00:00
|
|
|
|
|
|
|
In older versions of Electron, `showSaveDialog` returned the path directly:
|
|
|
|
|
|
|
|
```js
|
|
|
|
var dialog = require('electron').remote.dialog;
|
|
|
|
|
|
|
|
function exportFile(workbook) {
|
|
|
|
var result = dialog.showSaveDialog();
|
|
|
|
XLSX.writeFile(workbook, result);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-02-09 08:33:59 +00:00
|
|
|
## Complete Example
|
|
|
|
|
|
|
|
:::note
|
|
|
|
|
2023-09-05 18:04:23 +00:00
|
|
|
This demo was tested in the following environments:
|
|
|
|
|
|
|
|
| OS and Version | Arch | Electron | Date |
|
|
|
|
|:---------------|:-----|:---------|:-----------|
|
|
|
|
| macOS 13.5.1 | x64 | `26.1.0` | 2023-09-03 |
|
2023-09-25 07:30:54 +00:00
|
|
|
| macOS 13.5.1 | ARM | `26.1.0` | 2023-09-03 |
|
2023-09-05 18:04:23 +00:00
|
|
|
| Windows 10 | x64 | `26.1.0` | 2023-09-03 |
|
2023-09-25 07:30:54 +00:00
|
|
|
| Windows 10 | ARM | `26.1.0` | 2023-09-24 |
|
2023-10-12 08:39:38 +00:00
|
|
|
| Linux (HoloOS) | x64 | `27.0.0` | 2023-10-11 |
|
2023-09-05 18:04:23 +00:00
|
|
|
| Linux (Debian) | ARM | `26.1.0` | 2023-09-03 |
|
2023-02-09 08:33:59 +00:00
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
This demo includes a drag-and-drop box as well as a file input box, mirroring
|
|
|
|
the [SheetJS Data Preview Live Demo](https://oss.sheetjs.com/sheetjs/)
|
|
|
|
|
|
|
|
The core data in this demo is an editable HTML table. The readers build up the
|
|
|
|
table using `sheet_to_html` (with `editable:true` option) and the writers scrape
|
|
|
|
the table using `table_to_book`.
|
|
|
|
|
|
|
|
The demo project is wired for `electron-forge` to build the standalone binary.
|
|
|
|
|
|
|
|
1) Download the demo files:
|
|
|
|
|
|
|
|
- [`package.json`](pathname:///electron/package.json) : project structure
|
|
|
|
- [`main.js`](pathname:///electron/main.js) : main process script
|
|
|
|
- [`index.html`](pathname:///electron/index.html) : window page
|
|
|
|
- [`index.js`](pathname:///electron/index.js) : script loaded in render context
|
|
|
|
|
2023-09-24 03:59:48 +00:00
|
|
|
:::caution pass
|
2023-02-09 08:33:59 +00:00
|
|
|
|
|
|
|
Right-click each link and select "Save Link As...". Left-clicking a link will
|
|
|
|
try to load the page in your browser. The goal is to save the file contents.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
|
|
|
These instructions can be run in a terminal window:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
mkdir sheetjs-electron
|
|
|
|
cd sheetjs-electron
|
|
|
|
curl -LO https://docs.sheetjs.com/electron/package.json
|
|
|
|
curl -LO https://docs.sheetjs.com/electron/main.js
|
|
|
|
curl -LO https://docs.sheetjs.com/electron/index.html
|
|
|
|
curl -LO https://docs.sheetjs.com/electron/index.js
|
|
|
|
```
|
|
|
|
|
2023-09-05 18:04:23 +00:00
|
|
|
2) Install dependencies:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npm install
|
|
|
|
```
|
2023-02-09 08:33:59 +00:00
|
|
|
|
|
|
|
3) To verify the app works, run in the test environment:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npx -y electron .
|
|
|
|
```
|
|
|
|
|
2023-09-05 18:04:23 +00:00
|
|
|
The app will show.
|
2023-02-09 08:33:59 +00:00
|
|
|
|
|
|
|
4) To build a standalone app, run the builder:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npm run make
|
|
|
|
```
|
|
|
|
|
2023-09-05 18:04:23 +00:00
|
|
|
This will create a package in the `out\make` folder.
|
|
|
|
|
|
|
|
:::caution pass
|
|
|
|
|
|
|
|
On Linux, the packaging step may require additional dependencies[^1]
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-09-25 07:30:54 +00:00
|
|
|
:::info pass
|
|
|
|
|
|
|
|
When the demo was last tested on Windows ARM, the generated binary targeted x64.
|
|
|
|
The program will run on ARM64 Windows.
|
|
|
|
|
|
|
|
:::
|
|
|
|
|
2023-09-05 18:04:23 +00:00
|
|
|
**Testing**
|
|
|
|
|
|
|
|
5) Download [the test file `pres.numbers`](https://sheetjs.com/pres.numbers)
|
|
|
|
|
|
|
|
6) Re-launch the application in the test environment:
|
|
|
|
|
|
|
|
```bash
|
|
|
|
npx -y electron .
|
|
|
|
```
|
|
|
|
|
|
|
|
_Electron API_
|
|
|
|
|
|
|
|
7) Click "Click here to select a file from your computer". With the file picker,
|
|
|
|
navigate to the Downloads folder and select `pres.numbers`.
|
|
|
|
|
|
|
|
The application should show data in a table.
|
|
|
|
|
|
|
|
8) Click "Export Data!" and click "Save" in the popup. By default, it will try
|
|
|
|
to write to `Untitled.xls` in the Downloads folder.
|
|
|
|
|
|
|
|
The app will show a popup once the data is exported. Open the file in a
|
|
|
|
spreadsheet editor and compare the data to the table shown in the application.
|
|
|
|
|
|
|
|
_Drag and Drop_
|
|
|
|
|
|
|
|
9) Close the application, end the terminal process and re-launch (see step 6)
|
|
|
|
|
|
|
|
10) Open the Downloads folder in a file explorer or finder window.
|
|
|
|
|
|
|
|
11) Click and drag the `pres.numbers` file from the Downloads folder to the
|
|
|
|
bordered "Drop a spreadsheet file" box. The file data should be displayed.
|
|
|
|
|
|
|
|
_File Input Element_
|
|
|
|
|
|
|
|
12) Close the application, end the terminal process and re-launch (see step 6)
|
|
|
|
|
|
|
|
13) Click "Choose File". With the file picker, navigate to the Downloads folder
|
|
|
|
and select `pres.numbers`.
|
2023-02-09 08:33:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
## Electron Breaking Changes
|
2023-01-05 03:57:48 +00:00
|
|
|
|
|
|
|
The first version of this demo used Electron 1.7.5. The current demo includes
|
2023-02-09 08:33:59 +00:00
|
|
|
the required changes for Electron 23.0.0.
|
2023-01-05 03:57:48 +00:00
|
|
|
|
|
|
|
There are no Electron-specific workarounds in the library, but Electron broke
|
|
|
|
backwards compatibility multiple times. A summary of changes is noted below.
|
|
|
|
|
2023-09-24 03:59:48 +00:00
|
|
|
:::caution pass
|
2023-01-05 03:57:48 +00:00
|
|
|
|
|
|
|
Electron 6.x changed the `dialog` API. Methods like `showSaveDialog` originally
|
|
|
|
returned an array of strings, but now returns a `Promise`. This change was not
|
|
|
|
documented.
|
|
|
|
|
|
|
|
Electron 9.0.0 and later require the preference `nodeIntegration: true` in order
|
|
|
|
to `require('xlsx')` in the renderer process.
|
|
|
|
|
|
|
|
Electron 12.0.0 and later also require `worldSafeExecuteJavascript: true` and
|
|
|
|
`contextIsolation: true`.
|
|
|
|
|
|
|
|
Electron 14+ must use `@electron/remote` instead of `remote`. An `initialize`
|
|
|
|
call is required to enable Developer Tools in the window.
|
|
|
|
|
|
|
|
:::
|
2023-09-05 18:04:23 +00:00
|
|
|
|
|
|
|
[^1]: See ["Makers"](https://www.electronforge.io/config/makers) in the Electron Forge documentation.
|