This commit is contained in:
SheetJS 2023-08-31 18:09:08 -04:00
parent 3f137265cc
commit 155b88ff3c
10 changed files with 244 additions and 63 deletions

@ -218,12 +218,31 @@ V8 engine. This demo uses the Rust integration to generate a command line tool.
This demo was last tested in the following deployments:
| Architecture | V8 Version | Date |
|:-------------|:-------------|:-----------|
| `darwin-x64` | `11.4.183.2` | 2023-05-22 |
| `darwin-mac` | `11.4.183.2` | 2023-05-22 |
| `linux-x64` | `11.4.183.2` | 2023-05-23 |
| `win10-x64` | `11.4.183.2` | 2023-05-23 |
| Architecture | V8 Version | Crate | Date |
|:-------------|:-------------|:---------|:-----------|
| `darwin-x64` | `11.4.183.2` | `0.71.2` | 2023-05-22 |
| `darwin-arm` | `11.4.183.2` | `0.71.2` | 2023-05-22 |
| `linux-x64` | `11.4.183.2` | `0.71.2` | 2023-05-23 |
| `linux-arm` | `11.7.439.6` | `0.75.1` | 2023-08-30 |
| `win10-x64` | `11.4.183.2` | `0.71.2` | 2023-05-23 |
| `win11-x64` | `11.7.439.6` | `0.75.1` | 2023-08-31 |
:::caution pass
Using crate version `0.71.2`, the Linux AArch64 build failed with an error:
```
error[E0080]: evaluation of constant value failed
|
1715 | assert!(size_of::<TypeId>() == size_of::<u64>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'assertion failed: size_of::<TypeId>() == size_of::<u64>()'
```
This was fixed in version `0.75.1` of the crate.
:::
</details>
@ -286,7 +305,7 @@ mv target/release/sheet2csv .
```bash
mv target/release/sheet2csv.exe .
./sheet2csv pres.numbers
.\sheet2csv.exe pres.numbers
```
</TabItem>
@ -312,6 +331,7 @@ This demo was last tested in the following deployments:
| `darwin-arm` | `1.34.1` | 2023-06-05 |
| `win10-x64` | `1.33.2` | 2023-05-08 |
| `linux-x64` | `1.33.2` | 2023-05-08 |
| `linux-arm` | `1.36.3` | 2023-08-30 |
</details>

@ -9,14 +9,14 @@ sidebar_custom_props:
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
Reading and writing files require native platform support. `XLSX.readFile` and
`XLSX.writeFile` include support for some APIs.
Reading from and writing to files requires native platform support.
For other APIs, user code can pass data to `XLSX.read` or use data generated by
`XLSX.write` directly. Both methods work with a number of common storage types.
SheetJS `readFile` and `writeFile` methods include support for some platforms.
Due to sandboxing and security settings, `readFile` does not work in the web
browser and `writeFile` is not guaranteed to work in all cases.
This demo looks at various web APIs. More specific approaches for deployments
like mobile apps are covered in their respective demos.
This demo looks at various web APIs for reading and writing files. We'll explore
how to pass data between SheetJS functions and various APIs.
:::note pass
@ -25,30 +25,65 @@ Some snippets are also available in the "Common Use Cases" section:
- [Data Import](/docs/solutions/input)
- [Data Export](/docs/solutions/output)
:::
Other demos cover APIs for local file access on special platforms:
## Web Browsers
:::warning pass
Not all web APIs are supported in all browsers. For example, Firefox does not
support the "File System Access API".
Even when a browser technically supports a web API, it may be disabled in the
client browser. Some APIs do not give any feedback.
- ["iOS and Android Apps"](/docs/demos/mobile/) covers mobile app frameworks
- ["Desktop and CLI Tools"](/docs/demos/desktop/) covers desktop apps and CLIs
:::
### Binary Data
## Binary Data
Modern browser APIs typically use typed arrays or `Blob` or `File` structures.
JavaScript engines represent binary data in a number of structures.
_Reading Binary Data_
### `Uint8Array`
`XLSX.read` supports `Uint8Array` and `ArrayBuffer` data. For `Blob` or `File`
objects, the underlying data must be pulled into an `ArrayBuffer`.
A `Uint8Array` is a Typed Array where each value is a 8-bit unsigned integer.
Server-side platforms including NodeJS typically use `Uint8Array`, or a subclass
such as `Buffer`, to represent data from files.
The callback-based approach uses a `FileReader`:
The SheetJS `read` method can read data from `Uint8Array` without special
options. The SheetJS `write` method can generate workbooks stored in
`Uint8Array` structures with the option `bookType: "buffer"`
### `ArrayBuffer`
An `ArrayBuffer` represents an array of bytes. Unlike `Uint8Array`, the bytes
are not immediately available. Typically the underlying data is pulled using
the `Uint8Array` constructor:
```js
const u8 = new Uint8Array(array_buffer);
```
The SheetJS `read` method can read data from `ArrayBuffer` without special
options, as it performs the aforementioned conversion. The SheetJS `write`
method can generate workbooks stored in `ArrayBuffer` structures with the
option `bookType: "array"`
### `Blob` and `File`
`Blob` is an opaque pointer to data. The data is not immediately accessible.
`File` extends `Blob` with support for storing file names and other metadata.
The SheetJS `read` method does not handle `Blob` or `File`. The underlying data
must be pulled into an `ArrayBuffer` before parsing. There are two approaches:
A) Modern browsers support the `arrayBuffer` method. It returns a promise that
resolves to `ArrayBuffer`:
```js
// usage: const wb = await blob_to_wb(blob);
async function blob_to_wb(blob) {
const ab = await blob.arrayBuffer(); // pull data from Blob
return XLSX.read(ab); // parse ArrayBuffer
}
```
B) For broader browser support, the `FileReader` API can pull `ArrayBuffer` data
using the `readAsArrayBuffer` method:
```js
// usage: file_to_wb(file, function(wb) { /* wb is a workbook object */ });
@ -64,7 +99,7 @@ function file_to_wb(file, callback) {
<details><summary><b>FileReaderSync in Web Workers</b> (click to show)</summary>
`FileReaderSync` is only available in Web Workers:
`FileReaderSync` is only available in Web Workers. It returns an `ArrayBuffer`:
```js
// assuming main thread called worker.postMessage({ file: file_object })
@ -84,9 +119,36 @@ includes a live demo.
</details>
<details><summary><b>IE10 Binary Strings</b> (click to show)</summary>
The SheetJS `write` method can generate a `Uint8Array` which can be passed to
the `Blob` constructor:
`XLSX.read` supports binary strings with `type: "binary"`:
```js
/* write workbook to Uint8Array */
const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
/* create array of parts */
const parts = [ u8 ]; // `Blob` constructor expects this
/* create Blob */
const blob = new Blob(parts, { type: "application/vnd.ms-excel" });
```
The `File` constructor accepts an additional `name` argument:
```js
/* write workbook to Uint8Array */
const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
/* create array of parts */
const parts = [ u8 ]; // `Blob` constructor expects this
/* create Blob */
const blob = new File(parts, "SheetJSFileExport.xlsx", { type: "application/vnd.ms-excel" });
```
### Binary Strings
Binary strings are strings where each character code is between `0` and `255`.
This structure is generated from the `FileReader#readAsBinaryString` method.
The SheetJS `read` method supports binary strings with `type: "binary"`. The
following snippet shows how `readAsBinaryString` can be paired with SheetJS:
```js
// usage: file_bs_to_wb(file, function(wb) { /* wb is a workbook object */ });
@ -100,28 +162,54 @@ function file_bs_to_wb(file, callback) {
}
```
</details>
The Promise-based approach uses `Blob#arrayBuffer`:
The SheetJS `write` method can generate binary strings using `type: "binary"`:
```js
// usage: const wb = await blob_to_wb(blob);
async function blob_to_wb(blob) {
return XLSX.read(await blob.arrayBuffer());
/* write workbook to binary string */
const bstr = XLSX.write(wb, { bookType: "xlsx", type: "binary" });
```
### Base64 Strings
Base64 strings are encoded using 64 display ASCII characters. This structure is
generated from `btoa`, the `FileReader#readAsDataURL` method, and many platform
APIs in mobile and desktop app frameworks.
The SheetJS `read` method supports Base64 strings with `type: "base64"`. The
following snippet shows how `readAsDataURL` can be paired with SheetJS:
```js
// usage: file_b64_to_wb(file, function(wb) { /* wb is a workbook object */ });
function file_b64_to_wb(file, callback) {
var reader = new FileReader();
reader.onload = function(e) {
/* e.target.result is a base64 string */
callback(XLSX.read(e.target.result, { type: "base64" }));
};
reader.readAsDataURL(file);
}
```
_Writing Binary Data_
`XLSX.write` can generate `Uint8Array` results by passing `type: "buffer"`.
A `Blob` can be created by using the constructor:
The SheetJS `write` method can generate Base64 strings using `type: "base64"`:
```js
const u8 = XLSX.write(workbook, { type: "buffer", bookType: "xlsx" });
const blob = new Blob([u8], { type: "application/vnd.ms-excel" });
/* write workbook to Base64 string */
const b64 = XLSX.write(wb, { bookType: "xlsx", type: "base64" });
```
## Web Browsers
:::warning pass
Not all web APIs are supported in all browsers. For example, Firefox does not
support the "File System Access API".
Even when a browser technically supports a web API, it may be disabled in the
client browser. Some APIs do not give any feedback.
:::
### HTML5 Download Attribute
_Writing Files_
@ -137,10 +225,10 @@ XLSX.writeFile(wb, "SheetJS.xlsx");
Under the hood, it creates a special URL and clicks a link. The library method
includes a few workarounds for legacy browsers
`XLSX.writeFile(wb, "SheetJS.xlsx");` is roughly equivalent to:
**`XLSX.writeFile(wb, "SheetJS.xlsx");`** is roughly equivalent to:
```js
/* write data -- note that writeFile infers bookType from filename */
/* write data -- `writeFile` infers bookType from filename but `write` cannot */
const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
/* create Blob */
const blob = new Blob([u8]);
@ -179,7 +267,8 @@ includes a live demo.
_Reading Files_
In the `change` event of `<input type="file">`, `target` hold a list of files:
In the `change` event of `<input type="file">`, the event object will have a
`target` property. The `files` property of `target` is a list of `File` objects.
```js
async function handleFileAsync(e) {
@ -199,7 +288,7 @@ input_dom_element.addEventListener("change", handleFileAsync, false);
_Reading Files_
The `dataTransfer` property of the `drop` event holds a list of files:
The `dataTransfer` property of the `drop` event holds a list of `File` objects:
```js
/* suppress default behavior for drag and drop events */
@ -225,16 +314,30 @@ drop_dom_element.addEventListener("dragenter", suppress, false);
### File System Access API
:::caution Limited Browser Support
:::warning Limited Browser Support
At the time of writing, browser support was fairly limited. Chrome introduced
the feature in version 86. Safari did not support File System Access API.
:::
:::caution
When this demo was last tested, Google Chrome did not add an entry to the
"Downloads" list. Nevertheless the actual file was written correctly.
:::
:::note
This demo was last tested on 2023 August 30 in Google Chrome.
:::
<details><summary><b>Live Example</b> (click to show) </summary>
This live example reads a file then tries to save as XLSX.
This live example reads a file then tries to save as XLSX. If the File System
Access API is not supported, the result will be a clear message.
```jsx live
function SheetJSRoundTripFileSystemAPI() { return window.showSaveFilePicker ? (
@ -340,6 +443,20 @@ is not recommended for new applications.
_Writing Files_
The API is callback-based. At a high level:
1) `window.requestFileSystem` requests access to the filesystem. The callback
receives a `FileSystem` object.
2) A file is created using the `getFile` method. The callback receives a
`FileSystemFileEntry` object representing the file.
3) A writer is created using the `createWriter` method of the file object. The
callback receives a `FileWriter` object representing a file handle for writing.
4) Data is written using the `write` method of the `FileWriter` object. Unlike
the other methods, callbacks are attached to the `FileWriter` object directly.
```js
// Request File System Access
window.requestFileSystem(window.PERSISTENT, 0, (fs) => {
@ -370,6 +487,21 @@ _Writing Files_
IE10 and IE11 support `navigator.msSaveBlob`. `XLSX.writeFile` will use this
method if it is available.
<details><summary><b>Implementation Details</b> (click to show)</summary>
**`XLSX.writeFile(wb, "SheetJS.xlsx");`** is roughly equivalent to:
```js
/* write data -- `writeFile` infers bookType from filename but `write` cannot */
const u8 = XLSX.write(wb, { bookType: "xlsx", type: "buffer" });
/* create Blob */
const blob = new Blob([u8]);
/* call msSaveBlob */
navigator.msSaveBlob(blob, "SheetJS.xlsx");
```
</details>
#### VBScript
_Reading and Writing Files_
@ -470,7 +602,7 @@ var wb = XLSX.readFile("sheetjs.xlsx");
XLSX.writeFile(wb, "sheetjs.csv");
```
The [ExtendScript demo](/docs/demos/extensions/extendscript) covers the "Common
The [ExtendScript demo](/docs/demos/extensions/extendscript) also covers "Common
Extensibility Platform" (CEP) and "Unified Extensibility Platform" (UXP) details.
### Chrome Extensions

@ -120,6 +120,7 @@ This demo was tested in the following deployments:
| `darwin-x64` | `2.7.0` | 2023-07-24 |
| `darwin-arm` | `2.7.0` | 2023-06-05 |
| `linux-x64` | `2.7.0` | 2023-06-02 |
| `linux-arm` | `2.7.0` | 2023-08-30 |
| `win10-x64` | `2.7.0` | 2023-07-24 |
:::

@ -723,6 +723,7 @@ This demo was last tested in the following deployments:
| `darwin-x64` | `0.75.1` | 2023-08-26 |
| `darwin-arm` | `0.73.0` | 2023-06-05 |
| `linux-x64` | `0.71.2` | 2023-05-23 |
| `linux-arm` | `0.75.1` | 2023-08-30 |
| `win10-x64` | `0.71.2` | 2023-05-23 |
:::

@ -98,6 +98,10 @@ This demo was tested in the following deployments:
| `darwin-arm` | `28ee0ee` | `1.20.4` | 2023-06-05 |
| `win10-x64` | `81d7606` | `1.20.2` | 2023-08-27 |
| `linux-x64` | `81d7606` | `1.21.0` | 2023-08-27 |
| `linux-arm` | `3dbe69d` | `1.21.1` | 2023-08-30 |
At the time of writing, Goja did not have proper version numbers. Versions are
identified by Git commit hashes.
:::

@ -341,6 +341,7 @@ This demo was tested in the following deployments:
| `darwin-x64` | `70af78b` | 2023-08-27 |
| `darwin-arm` | `869312f` | 2023-06-05 |
| `linux-x64` | `70af78b` | 2023-08-27 |
| `linux-arm` | `70af78b` | 2023-08-27 |
:::
@ -362,6 +363,12 @@ On HoloOS (and other Arch Linux distros):
sudo pacman -Syu cmake git ninja icu python zip readline
```
On Debian and Ubuntu:
```bash
sudo apt install cmake git ninja-build libicu-dev python zip libreadline-dev
```
</details>
1) Make a project directory:

@ -7,7 +7,7 @@ pagination_next: solutions/input
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
:::warning
:::warning pass
In a production application, it is strongly recommended to use a binding for a
more performant engine like [`v8`](/docs/demos/engines/v8#rust)
@ -19,7 +19,6 @@ Boa is a pure-Rust JavaScript engine.
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
parsed and evaluated in a Boa context.
## Integration Details
_Initialize Engine_
@ -115,9 +114,11 @@ This demo was tested in the following deployments:
| Architecture | Date |
|:-------------|:-----------|
| `darwin-x64` | 2023-07-19 |
| `darwin-x64` | 2023-08-31 |
| `darwin-arm` | 2023-07-05 |
| `linux-x64` | 2023-07-05 |
| `linux-arm` | 2023-08-30 |
| `win10-x64` | 2023-08-31 |
:::
@ -151,7 +152,14 @@ curl -L -o src/main.rs https://docs.sheetjs.com/boa/main.rs
```bash
curl -LO https://sheetjs.com/pres.xlsx
cargo run
cargo run --release
```
After a short wait, the contents will be displayed in CSV form.
:::caution pass
The default debug build is not optimized and can elicit stack overflow errors.
It is strongly encouraged to use `--release` when possible.
:::

@ -44,7 +44,7 @@ These instructions were tested on the following platforms:
| MacOS 10.13 (x64) | 2023-04-04 |
| MacOS 13.0 (ARM64) | 2023-04-13 |
| Windows 10 (x64) + WSL Ubuntu | 2023-07-23 |
| Windows 11 (x64) + WSL Ubuntu | 2023-04-04 |
| Windows 11 (x64) + WSL Ubuntu | 2023-08-31 |
With some additional dependencies, the unminified build is reproducible and
tests will pass in Windows XP with NodeJS 5.10.0.
@ -75,6 +75,17 @@ sudo add-apt-repository --remove ppa:mercurial-ppa/releases
C) Install NodeJS
:::info pass
When this was last tested, the script showed a deprecation notice.
**The script worked as expected.**
The official workaround does not currently work with WSL. When the issues are
resolved, the instructions will be updated.
:::
```bash
# Install bootstrap NodeJS and NPM within the WSL
curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -
@ -250,13 +261,10 @@ git clone https://git.sheetjs.com/sheetjs/sheetjs
cd sheetjs
```
1) Install NodeJS modules for building the scripts
1) Install NodeJS modules for building the scripts:
```bash
# Install dev dependencies
npm i
# Install global dependencies
sudo npm i -g mocha@2.5.3 voc @sheetjs/uglify-js
```

@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"
[dependencies]
v8 = "0.71.2"
v8 = "0.75.1"
[[bin]]
name = "sheet2csv"

@ -7,7 +7,7 @@ POSTAMBLE=-framework CoreFoundation
UNAME__S := $(shell uname -s)
ifeq ($(UNAME__S),Linux)
MYCC=g++
POSTAMBLE=-licuuc -licudata -licuio -licutu -licui18n
POSTAMBLE=-pthread -licuuc -licudata -licuio -licutu -licui18n
endif
.PHONY: doit