Command-Line testing grid

This commit is contained in:
SheetJS 2024-05-29 01:10:39 -04:00
parent 945e5f02eb
commit 1a80a55e76
20 changed files with 1239 additions and 486 deletions

14
docz/data/cli.js Normal file

@ -0,0 +1,14 @@
import { read, utils } from 'xlsx';
import url from './cli.xls';
import React, { useEffect, useState } from 'react';
const FrameworkData = () => {
const [fw, setFW] = useState("");
useEffect(() => { (async() => {
const wb = read(await (await fetch(url)).arrayBuffer(), { dense: true });
setFW(utils.sheet_to_html(wb.Sheets["Frameworks"]));
})(); }, []);
return ( <div dangerouslySetInnerHTML={{__html: fw}}/> );
};
export default FrameworkData;

124
docz/data/cli.xls Normal file

@ -0,0 +1,124 @@
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>10620</WindowHeight>
<WindowWidth>11020</WindowWidth>
<WindowTopX>2260</WindowTopX>
<WindowTopY>19600</WindowTopY>
<ActiveSheet>1</ActiveSheet>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s16">
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
</Style>
<Style ss:ID="s17">
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
</Style>
<Style ss:ID="s19">
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000" ss:Bold="1"/>
</Style>
<Style ss:ID="s20">
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#467886" ss:Underline="Single"/>
</Style>
</Styles>
<Worksheet ss:Name="Frameworks">
<Table ss:ExpandedColumnCount="7" ss:ExpandedRowCount="10" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
<Column ss:Index="2" ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Row>
<Cell ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s17"><Data ss:Type="String">Framework</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/nexe"><Data ss:Type="String">nexe</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/boxednode"><Data ss:Type="String">boxednode</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/pkg"><Data ss:Type="String">pkg</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/nodesea#complete-example"><Data ss:Type="String">NodeJS SEA</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/bunsea#complete-example"><Data ss:Type="String">Bun SEA</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"></Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/cli/denosea#complete-example"><Data ss:Type="String">Deno SEA</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/v8#snapshots"><Data ss:Type="String">V8 Engine</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook>

@ -0,0 +1,187 @@
---
title: Spreadsheet Tools with Nexe
sidebar_label: nexe
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
sidebar_custom_props:
summary: Prebuilt NodeJS packages
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
export const r = {style: {color:"red"}};
export const B = {style: {fontWeight:"bold"}};
`nexe`[^1] is a tool for generating command-line tools that embed scripts.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses `nexe` and SheetJS to create a standalone CLI tool for parsing
spreadsheets and converting to other formats.
:::info pass
The latest prebuilt package matches NodeJS version `14.15.3`.
`nexe` can build the required packages for newer NodeJS versions.
:::
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Version | NodeJS | Source | Date |
|:-------------|:-------------|:----------|:----------|:-----------|
| `darwin-x64` | `4.0.0-rc.6` | `14.15.3` | Pre-built | 2024-05-28 |
| `darwin-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-25 |
| `win10-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-04-18 |
| `win11-arm` | `4.0.0-rc.6` | `20.10.0` | Compiled | 2024-05-28 |
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-21 |
| `linux-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-26 |
:::
## Integration Details
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
required from scripts. `nexe` will automatically handle packaging.
### Script Requirements
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
be bundled using `nexe`.
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
is a simple command-line tool for reading and writing spreadsheets.
## Complete Example
0) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
```bash
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
```
2) Install the dependencies:
<Tabs groupId="pm">
<TabItem value="npm" label="npm">
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
</Tabs>
3) Create the standalone program:
```bash
npx nexe -t 14.15.3 xlsx-cli.js
```
<details open>
<summary><b>Building from source (click to hide)</b></summary>
When the demo was tested on ARM targets, the Nexe pre-built packages were
missing. For unsupported NodeJS versions, packages must be built from source:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
npx nexe xlsx-cli.js --build --python=$(which python3) --make="-j8"
```
</TabItem>
<TabItem value="win" label="Windows">
On Windows x64, the `--build` flag suffices:
```bash
npx nexe xlsx-cli.js --build --make="-j8"
```
On Windows ARM, the target `windows-arm64-20.10.0` must be specified:
```bash
npx nexe xlsx-cli.js --build --make="-j8" --target=windows-arm64-20.10.0
```
**`vcbuild.bat` issues**
The Windows ARM build may fail with a `vcbuild.bat` error:
```
Error: vcbuild.bat nosign release arm64 exited with code: 1
```
Pass the `-v` flag for more details. In the most recent test, the error stemmed
from a Python version mismatch:
```
Node.js configure: found Python 2.7.18
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6
```
The resolved version of Python can be found with
```cmd
where python
```
In the most recent test, a Python 2 version appeared first. This was fixed by
finding the Python 3 location and prepending it to `PATH`:
```cmd
set PATH="C:\correct\path\to\python\three";%PATH%
```
</TabItem>
</Tabs>
</details>
This generates `xlsx-cli` or `xlsx-cli.exe` depending on platform.
5) Run the generated program, passing `pres.numbers` as the argument:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
./xlsx-cli pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```powershell
.\xlsx-cli.exe pres.numbers
```
</TabItem>
</Tabs>
[^1]: The project does not have a website. The [source repository](https://github.com/nexe/nexe) is publicly available.
[^2]: The NodeJS website hosts [prebuilt installers](https://nodejs.org/en/download/prebuilt-installer).

@ -0,0 +1,169 @@
---
title: Packing Sheets with pkg
sidebar_label: pkg
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
sidebar_custom_props:
summary: Prebuilt NodeJS packages
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
export const r = {style: {color:"red"}};
export const B = {style: {fontWeight:"bold"}};
`pkg`[^1] is a tool for generating command-line tools that embed scripts.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses `pkg` and SheetJS to create a standalone CLI tool for parsing
spreadsheets and converting to other formats.
:::caution pass
With the official release of [NodeJS SEA](/docs/demos/cli/nodesea), Vercel opted
to deprecate `pkg`. It is still useful for deploying apps embedding NodeJS v18
or earlier since those versions do not support NodeJS SEA.
:::
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `5.8.1` | `18.5.0` | 2024-05-28 |
| `darwin-arm` | `5.8.1` | `18.5.0` | 2024-05-25 |
| `win10-x64` | `5.8.1` | `18.5.0` | 2024-04-18 |
| `win11-arm` | `5.8.1` | `18.5.0` | 2024-05-28 |
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-03-21 |
| `linux-arm` | `5.8.1` | `18.5.0` | 2024-05-26 |
:::
## Integration Details
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
required from scripts. `pkg` will automatically handle packaging.
### Script Requirements
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
be bundled using `pkg`.
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
is a simple command-line tool for reading and writing spreadsheets.
### Limitations
:::danger pass
When this demo was last tested, `pkg` failed with an error referencing `node20`:
```
> Targets not specified. Assuming:
node20-linux-arm64, node20-macos-arm64, node20-win-arm64
> Error! No available node version satisfies 'node20'
```
**`pkg` does not support NodeJS 20 or 22!**
The local NodeJS version must be rolled back to version 18.
If `nvm` or `nvm-windows` was used to install NodeJS:
```bash
nvm install 18
nvm use 18
```
Otherwise, on macOS and Linux, `n` can manage the global installation:
```bash
sudo npm i -g n
sudo n 18
```
On Windows, it is recommended to use a prebuilt installer[^2]
:::
## Complete Example
0) Downgrade NodeJS to major version 18 or earlier.
1) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
2) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
```bash
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
```
3) Install the dependencies:
<Tabs groupId="pm">
<TabItem value="npm" label="npm">
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
</Tabs>
4) Create the standalone program:
```bash
npx pkg xlsx-cli.js
```
This generates `xlsx-cli-linux`, `xlsx-cli-macos`, and `xlsx-cli-win.exe` .
5) Run the generated program, passing `pres.numbers` as the argument:
<Tabs groupId="os">
<TabItem value="linux" label="Linux">
```bash
./xlsx-cli-linux pres.numbers
```
</TabItem>
<TabItem value="macos" label="macOS">
```bash
./xlsx-cli-macos pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```powershell
.\xlsx-cli-win.exe pres.numbers
```
</TabItem>
</Tabs>
[^1]: The project does not have a website. The [source repository](https://github.com/vercel/pkg) is publicly available.
[^2]: The NodeJS website hosts [prebuilt installers](https://nodejs.org/en/download/prebuilt-installer).

@ -0,0 +1,214 @@
---
title: Sheets in a Box with boxednode
sidebar_label: boxednode
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
sidebar_custom_props:
summary: NodeJS binaries with scripts, built from source
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
export const r = {style: {color:"red"}};
export const B = {style: {fontWeight:"bold"}};
`boxednode`[^1] is a tool for generating command-line tools that embed scripts.
It automates the process of building NodeJS from source.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses `boxednode` and SheetJS to create a standalone CLI tool for
parsing spreadsheets and converting to other formats.
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:----------|:-----------|
| `darwin-x64` | `2.4.0` | `22.2.0` | 2024-05-28 |
| `darwin-arm` | `2.4.3` | `22.2.0` | 2024-05-25 |
| `win10-x64` | `2.4.2` | `16.20.2` | 2024-04-18 |
| `linux-x64` | `2.4.0` | `21.7.1` | 2024-03-21 |
| `linux-arm` | `2.4.3` | `20.13.1` | 2024-05-26 |
:::
## Integration Details
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
required from scripts. `boxednode` will automatically handle packaging.
### Script Requirements
Scripts that exclusively use SheetJS libraries and NodeJS built-in modules can
be bundled using `boxednode`
The demo script [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js) runs in NodeJS. It
is a simple command-line tool for reading and writing spreadsheets.
## Complete Example
0) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
```bash
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
```
2) Install the dependencies:
<Tabs groupId="pm">
<TabItem value="npm" label="npm">
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
</Tabs>
3) Create the standalone program:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli
```
:::caution pass
When this demo was last tested in `linux-arm`, the build failed with an error:
<pre>
../deps/v8/src/base/small-vector.h: In instantiation of <span {...B}>class v8::base::SmallVector&lt;std::pair&lt;const v8::internal::compiler::turboshaft::PhiOp*, const v8::internal::compiler::turboshaft::OpIndex&gt;, 16&gt;</span>:
<span {...B}>../deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h:444:11:</span> required from here
<span {...B}>../deps/v8/src/base/macros.h:206:55:</span> <span style={{...r.style,...B.style}}>error:</span> static assertion failed: T should be trivially copyable
{" 206 |"} static_assert(::v8::base::is_trivially_copyable&lt;T&gt;::<span style={{...r.style,...B.style}}>value</span>, \\
{" |"} ^~~~~
</pre>
This affects NodeJS `22.2.0`, but does not affect `20.13.1`. It affects the
[V8 JavaScript Engine](/docs/demos/engines/v8#build-v8).
The `-n` flag controls the target NodeJS version. For this demo, the following
command uses NodeJS `20.13.1`:
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli -n 20.13.1
```
:::
</TabItem>
<TabItem value="win" label="Windows">
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
```
:::info pass
The Windows 10 build requires Visual Studio with "Desktop development with C++"
workload, Python 3.11, and NASM[^2].
**The build command must be run in "x64 Native Tools Command Prompt"**
:::
:::caution pass
When the demo was last tested, the build failed:
```
Not an executable Python program
Could not find Python.
```
By default, Windows aliases `python` to a Microsoft Store installer. If the
official installer was used, the alias should be disabled manually:
1) Open Start menu and type "app alias". Click "Manage app execution aliases".
2) Disable the App Installer for all items with `python` in the name.
Using Python 3.12, the build fails with an error:
```
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
```
In the most recent test, Python 3.11.8 was installed from the official site.
:::
:::caution pass
When the demo was last tested on Windows, the build failed:
```
error MSB8020: The build tools for Visual Studio 2019 (Platform Toolset = 'v142') cannot be found. To build using the v142 build tools, please install Visual Studio 2019 build tools.
```
This error was fixed by installing the `v142` build tools through the Visual
Studio installer.
:::
:::caution pass
In the most recent Windows test against NodeJS `20.8.0`, the build failed due
to an issue in the OpenSSL dependency:
```
...\node-v20.8.0\deps\openssl\openssl\crypto\cversion.c(75,33): error C2153: integer literals must have at least one digit [...\node-v20.8.0\deps\openssl\openssl.vcxproj]
```
SheetJS libraries are compatible with NodeJS versions dating back to `v0.8`. The
workaround is to select NodeJS `v16.20.2` using the `-n` flag. This version was
was chosen since NodeJS `v18` upgraded the OpenSSL dependency.
:::
</TabItem>
</Tabs>
4) Run the generated program, passing `pres.numbers` as the argument:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
./xlsx-cli pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```powershell
.\xlsx-cli.exe pres.numbers
```
</TabItem>
</Tabs>
[^1]: The project does not have a website. The [source repository](https://github.com/mongodb-js/boxednode) is publicly available.
[^2]: Downloads can be found [at the main NASM project website](https://www.nasm.us/)

@ -158,7 +158,7 @@ This demo was tested in the following deployments:
| Architecture | NodeJS | Date |
|:-------------|:----------|:-----------|
| `darwin-x64` | `20.11.1` | 2024-03-17 |
| `darwin-x64` | `22.2.0` | 2024-05-28 |
| `win10-x64` | `20.12.0` | 2024-03-26 |
| `win11-x64` | `20.13.1` | 2024-05-22 |
| `linux-x64` | `20.11.1` | 2024-03-18 |
@ -237,7 +237,7 @@ node sheet2csv.js pres.numbers
The script should display CSV contents from the first sheet:
```
```text title="Expected Output"
Name,Index
Bill Clinton,42
GeorgeW Bush,43

@ -0,0 +1,131 @@
---
title: BunJS SEA
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
sidebar_custom_props:
summary: BunJS Single-file Executables
---
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
[BunJS](https://bun.sh/docs/bundler/executables) is a JavaScript runtime with
support for compiling scripts into self-contained executables.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses the Bun compiler and SheetJS to create a standalone CLI tool for
parsing spreadsheets and generating CSV rows.
:::info pass
It is strongly recommended to install BunJS on systems using SheetJS libraries
in command-line tools. This workaround should only be considered if a standalone
binary is considered desirable.
:::
:::caution BunJS support is considered experimental.
Great open source software grows with user tests and reports. Any issues should
be reported to the BunJS project for further diagnosis.
:::
## Integration Details
The [SheetJS BunJS module](/docs/getting-started/installation/bun) can be
imported from BunJS scripts.
`bun build --compile` generates a standalone executable that includes the BunJS
runtime, user JS code and supporting scripts and assets
### Script Requirements
Scripts that exclusively use SheetJS libraries and BunJS built-in modules can be
bundled using BunJS. The module should be required directly:
<CodeBlock language="ts">{`\
const XLSX = require("xlsx");`}
</CodeBlock>
For example, the following script accepts one command line argument, parses the
specified file using the SheetJS `readFile` method[^1], generates CSV text from
the first worksheet using `sheet_to_csv`[^2], and prints to terminal:
<CodeBlock language="ts" title="sheet2csv.ts">{`\
const XLSX = require("xlsx");
\n\
/* process.argv[2] is the first argument to the script */
const filename = process.argv[2];
\n\
/* read file */
const wb = XLSX.readFile(filename);
\n\
/* generate CSV of first sheet */
const ws = wb.Sheets[wb.SheetNames[0]];
const csv = XLSX.utils.sheet_to_csv(ws);
\n\
/* print to terminal */
console.log(csv);`}
</CodeBlock>
## Complete Example
:::note Tested Deployments
This demo was last tested in the following deployments:
| Architecture | BunJS | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `1.1.10` | 2024-05-28 |
:::
0) Install or update BunJS.[^3]
1) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
2) Save the [contents of the `sheet2csv.ts` code block](#script-requirements)
to `sheet2csv.ts` in the project folder.
3) Install the SheetJS dependency:
<CodeBlock language="bash">{`\
bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
4) Test the script with `bun run`:
```bash
bun run sheet2csv.ts pres.numbers
```
The script should display CSV contents from the first sheet:
```text title="Expected Output"
Name,Index
Bill Clinton,42
GeorgeW Bush,43
Barack Obama,44
Donald Trump,45
Joseph Biden,46
```
5) Compile and run `sheet2csv`:
```bash
bun build ./sheet2csv.ts --compile --outfile sheet2csv
./sheet2csv pres.numbers
```
The program should display the same CSV contents as the script (from step 2)
[^1]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
[^2]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
[^3]: See ["Installation"](https://bun.sh/docs/installation) in the BunJS documentation for instructions.

@ -1,5 +1,5 @@
---
title: Deno Compiler
title: Deno SEA
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
sidebar_custom_props:
@ -69,7 +69,7 @@ const wb = XLSX.readFile(filename);
\n\
/* generate CSV of first sheet */
const ws = wb.Sheets[wb.SheetNames[0]];
const csv = utils.sheet_to_csv(ws);
const csv = XLSX.utils.sheet_to_csv(ws);
\n\
/* print to terminal */
console.log(csv);`}
@ -99,7 +99,7 @@ This demo was last tested in the following deployments:
| Architecture | Deno | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `1.43.1` | 2024-05-08 |
| `darwin-x64` | `1.43.6` | 2024-05-28 |
| `darwin-arm` | `1.43.6` | 2024-05-23 |
| `win10-x64` | `1.41.3` | 2024-03-24 |
| `win11-x64` | `1.43.6` | 2024-05-25 |
@ -125,7 +125,7 @@ deno run -r --allow-read https://docs.sheetjs.com/cli/sheet2csv.ts pres.numbers
The script should display CSV contents from the first sheet:
```
```text title="Expected Output"
Name,Index
Bill Clinton,42
GeorgeW Bush,43

@ -1,5 +1,7 @@
---
title: Command-Line Tools
title: Sheets on the Command Line
sidebar_label: Command-Line Tools
hide_table_of_contents: true
pagination_prev: demos/desktop/index
pagination_next: demos/data/index
---
@ -9,6 +11,7 @@ import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
import FrameworkData from '/data/cli.js'
export const r = {style: {color:"red"}};
export const B = {style: {fontWeight:"bold"}};
@ -45,10 +48,16 @@ Demos for common standalone CLI tools are included in separate pages:
</li>);
})}</ul>
#### Platform Support
The following frameworks have been tested on the following platforms:
<FrameworkData/>
:::tip pass
The [`xlsx-cli`](https://cdn.sheetjs.com/xlsx-cli/) NodeJS script is available
as a package on the SheetJS CDN. It is an easy-to-use command-line tool for
as a package on the SheetJS CDN. It is a straightforward command-line tool for
translating files between supported spreadsheet file formats.
:::
@ -65,457 +74,33 @@ server-side scripting platform cannot be installed on the target computer.
:::
## NodeJS
#### NodeJS
There are a few popular tools for compiling NodeJS scripts to CLI programs.
This demo has been organized by framework:
The demo script presents a friendly command line interface including flags:
- [`boxednode`](/docs/demos/cli/boxednode)
- [`nexe`](/docs/demos/cli/nexe)
- [`pkg`](/docs/demos/cli/pkg)
```bash
$ ./xlsx-cli -h
Usage: xlsx-cli [options] <file> [sheetname]
#### V8
Options:
-V, --version output the version number
-f, --file <file> use specified workbook
-s, --sheet <sheet> print specified sheet (default first sheet)
...
```
**[The exposition has been moved to the "V8" demo.](/docs/demos/engines/v8#snapshots)**
:::note Tested Deployments
#### BunJS
This demo was tested in the following deployments:
<Tabs groupId="njs">
<TabItem value="nexe" label="Nexe">
| Architecture | Version | NodeJS | Source | Date |
|:-------------|:-------------|:----------|:----------|:-----------|
| `darwin-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-15 |
| `darwin-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-25 |
| `win10-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-04-18 |
| `win11-arm` | `4.0.0-rc.6` | `20.10.0` | Compiled | 2024-05-28 |
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-03-21 |
| `linux-arm` | `4.0.0-rc.6` | `18.20.3` | Compiled | 2024-05-26 |
</TabItem>
<TabItem value="pkg" label="pkg">
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `5.8.1` | `18.5.0` | 2024-03-15 |
| `darwin-arm` | `5.8.1` | `18.5.0` | 2024-05-25 |
| `win10-x64` | `5.8.1` | `18.5.0` | 2024-04-18 |
| `win11-arm` | `5.8.1` | `18.5.0` | 2024-05-28 |
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-03-21 |
| `linux-arm` | `5.8.1` | `18.5.0` | 2024-05-26 |
</TabItem>
<TabItem value="boxednode" label="boxednode">
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:----------|:-----------|
| `darwin-x64` | `2.4.0` | `21.7.1` | 2024-03-15 |
| `darwin-arm` | `2.4.3` | `22.2.0` | 2024-05-25 |
| `win10-x64` | `2.4.2` | `16.20.2` | 2024-04-18 |
| `linux-x64` | `2.4.0` | `21.7.1` | 2024-03-21 |
| `linux-arm` | `2.4.3` | `20.13.1` | 2024-05-26 |
</TabItem>
</Tabs>
:::
0) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
1) Download [`xlsx-cli.js`](pathname:///cli/xlsx-cli.js)
```bash
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
```
2) Install the dependencies:
<Tabs groupId="pm">
<TabItem value="npm" label="npm">
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2`}
</CodeBlock>
</TabItem>
</Tabs>
3) Follow tooling steps:
<Tabs groupId="njs">
<TabItem value="nexe" label="Nexe">
Run `nexe` and manually specify NodeJS version 14.15.3
```bash
npx nexe -t 14.15.3 xlsx-cli.js
```
This generates `xlsx-cli` or `xlsx-cli.exe` depending on platform.
:::caution pass
When the demo was tested on ARM targets, the Nexe pre-built packages were
missing. The package must be built from source:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
npx nexe xlsx-cli.js --build --python=$(which python3) --make="-j8"
```
</TabItem>
<TabItem value="win" label="Windows">
```bash
npx nexe xlsx-cli.js --build --make="-j8"
```
</TabItem>
</Tabs>
:::
:::caution pass
On Windows ARM, the target `windows-arm64-20.10.0` must be specified:
```bash
npx nexe xlsx-cli.js --build --make="-j8" --target=windows-arm64-20.10.0
```
The Windows build may fail with a `vcbuild.bat` error:
```
Error: vcbuild.bat nosign release arm64 exited with code: 1
```
Pass the `-v` flag for more details. In the most recent test, the error stemmed
from a Python version mismatch:
```
Node.js configure: found Python 2.7.18
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6
```
The resolved version of Python can be found with
```cmd
where python
```
In the most recent test, a Python 2 version appeared first. This was fixed by
finding the Python 3 location and prepending it to `PATH`:
```cmd
set PATH="C:\correct\path\to\python\three";%PATH%
```
:::
</TabItem>
<TabItem value="pkg" label="pkg">
:::danger pass
When this demo was last tested, `pkg` failed with an error referencing `node20`:
```
> Targets not specified. Assuming:
node20-linux-arm64, node20-macos-arm64, node20-win-arm64
> Error! No available node version satisfies 'node20'
```
**`pkg` does not support NodeJS 20!**
The local NodeJS version must be rolled back to version 18.
If `n` is installed:
```bash
sudo n 18
```
If `nvm` was used to install NodeJS:
```bash
nvm install 18
nvm use 18
```
:::
Run `pkg`:
```bash
npx pkg xlsx-cli.js
```
This generates `xlsx-cli-linux`, `xlsx-cli-macos`, and `xlsx-cli-win.exe` .
</TabItem>
<TabItem value="boxednode" label="boxednode">
Run `boxednode`:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli
```
:::caution pass
When this demo was last tested in `linux-arm`, the build failed with an error:
<pre>
../deps/v8/src/base/small-vector.h: In instantiation of <span {...B}>class v8::base::SmallVector&lt;std::pair&lt;const v8::internal::compiler::turboshaft::PhiOp*, const v8::internal::compiler::turboshaft::OpIndex&gt;, 16&gt;</span>:
<span {...B}>../deps/v8/src/compiler/turboshaft/loop-unrolling-reducer.h:444:11:</span> required from here
<span {...B}>../deps/v8/src/base/macros.h:206:55:</span> <span style={{...r.style,...B.style}}>error:</span> static assertion failed: T should be trivially copyable
{" 206 |"} static_assert(::v8::base::is_trivially_copyable&lt;T&gt;::<span style={{...r.style,...B.style}}>value</span>, \\
{" |"} ^~~~~
</pre>
This affects NodeJS `22.2.0`, but does not affect `20.13.1`. It affects the
[V8 JavaScript Engine](https://docs.sheetjs.com/docs/demos/engines/v8#build-v8)
and cannot easily be patched using `boxednode`.
The `-n` flag controls the target NodeJS version. For this demo, the following
command uses NodeJS `20.13.1`:
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli -n 20.13.1
```
:::
</TabItem>
<TabItem value="win" label="Windows">
```bash
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli.exe -n 16.20.2
```
:::info pass
The Windows 10 build requires Visual Studio with "Desktop development with C++"
workload, Python 3.11, and NASM[^1].
**The build command must be run in "x64 Native Tools Command Prompt"**
:::
:::caution pass
When the demo was last tested, the build failed:
```
Not an executable Python program
Could not find Python.
```
By default, Windows aliases `python` to a Microsoft Store installer. If the
official installer was used, the alias should be disabled manually:
1) Open Start menu and type "app alias". Click "Manage app execution aliases".
2) Disable the App Installer for all items with `python` in the name.
Using Python 3.12, the build fails with an error:
```
Please use python3.11 or python3.10 or python3.9 or python3.8 or python3.7 or python3.6.
```
In the most recent test, Python 3.11.8 was installed from the official site.
:::
:::caution pass
When the demo was last tested on Windows, the build failed:
```
error MSB8020: The build tools for Visual Studio 2019 (Platform Toolset = 'v142') cannot be found. To build using the v142 build tools, please install Visual Studio 2019 build tools.
```
This error was fixed by installing the `v142` build tools through the Visual
Studio installer.
:::
:::caution pass
In the most recent Windows test against NodeJS `20.8.0`, the build failed due
to an issue in the OpenSSL dependency:
```
...\node-v20.8.0\deps\openssl\openssl\crypto\cversion.c(75,33): error C2153: integer literals must have at least one digit [...\node-v20.8.0\deps\openssl\openssl.vcxproj]
```
SheetJS libraries are compatible with NodeJS versions dating back to `v0.8`. The
workaround is to select NodeJS `v16.20.2` using the `-n` flag. This version was
was chosen since NodeJS `v18` upgraded the OpenSSL dependency.
:::
</TabItem>
</Tabs>
</TabItem>
</Tabs>
4) Run the generated program, passing `pres.numbers` as the argument. For
example, `nexe` generates `xlsx-cli` in macOS so the command is:
```bash
./xlsx-cli pres.numbers
```
`nexe` generates `xlsx-cli.exe` in Windows, so the command is:
```powershell
.\xlsx-cli.exe pres.numbers
```
## V8
The [V8](/docs/demos/engines/v8) demo covers standalone programs that embed the
V8 engine. This demo uses the Rust integration to generate a command line tool.
:::note Tested Deployments
This demo was last tested in the following deployments:
| Architecture | V8 Version | Crate | Date |
|:-------------|:--------------|:---------|:-----------|
| `darwin-x64` | `12.3.219.9` | `0.88.0` | 2024-03-15 |
| `darwin-arm` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `win10-x64` | `12.3.219.9` | `0.88.0` | 2024-03-24 |
| `win11-x64` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `linux-x64` | `12.3.219.9` | `0.88.0` | 2024-03-18 |
| `linux-arm` | `12.6.228.3` | `0.92.0` | 2024-05-26 |
:::
0) Make a new folder for the project:
```bash
mkdir sheetjs2csv
cd sheetjs2csv
```
1) Download the following scripts:
- [`Cargo.toml`](pathname:///cli/Cargo.toml)
- [`snapshot.rs`](pathname:///cli/snapshot.rs)
- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs)
```bash
curl -o Cargo.toml https://docs.sheetjs.com/cli/Cargo.toml
curl -o snapshot.rs https://docs.sheetjs.com/cli/snapshot.rs
curl -o sheet2csv.rs https://docs.sheetjs.com/cli/sheet2csv.rs
```
2) Download the SheetJS Standalone script and move to the project directory:
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
</ul>
<CodeBlock language="bash">{`\
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}
</CodeBlock>
3) Build the V8 snapshot:
```bash
cargo build --bin snapshot
cargo run --bin snapshot
```
:::caution pass
With some versions of the `v8` crate, 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>()'
```
Versions `0.75.1` and `0.82.0` are known to work.
:::
4) Build `sheet2csv` (`sheet2csv.exe` in Windows):
```bash
cargo build --release --bin sheet2csv
```
5) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
6) Test the application:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
mv target/release/sheet2csv .
./sheet2csv pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```bash
mv target/release/sheet2csv.exe .
.\sheet2csv.exe pres.numbers
```
</TabItem>
</Tabs>
**[The exposition has been moved to a separate page.](/docs/demos/cli/bunsea)**
#### Deno
**[The exposition has been moved to a separate page.](/docs/demos/cli/deno)**
**[The exposition has been moved to a separate page.](/docs/demos/cli/denosea)**
## Dedicated Engines
#### Dedicated Engines
The following demos for JS engines produce standalone programs:
- [V8](/docs/demos/engines/v8)
- [Duktape](/docs/demos/engines/duktape)
- [ChakraCore](/docs/demos/engines/chakra)
- [QuickJS](/docs/demos/engines/quickjs)
- [Goja](/docs/demos/engines/goja)
- [JavaScriptCore](/docs/demos/engines/jsc)
[^1]: Downloads can be found [at the main NASM project website](https://www.nasm.us/)

@ -19,9 +19,7 @@ data from spreadsheets.
The ["Complete Example"](#complete-example) section includes a complete
command-line tool for reading data from spreadsheets and exporting to Excel XLSB
workbooks.
The ["Bindings"](#bindings) section covers bindings for other ecosystems.
workbooks. ["Bindings"](#bindings) covers bindings for other ecosystems.
## Integration Details

@ -1,7 +1,7 @@
---
title: Blazing Fast Data Processing with V8
sidebar_label: C++ + V8
description: Process structured data in C++ or Rust programs. Seamlessly integrate spreadsheets by paring V8 and SheetJS. Modernize workflows while preserving Excel compatibility.
description: Process structured data in C++ or Rust programs. Seamlessly integrate spreadsheets by pairing V8 and SheetJS. Modernize workflows while maintaining Excel compatibility.
pagination_prev: demos/bigdata/index
pagination_next: solutions/input
---
@ -30,6 +30,18 @@ covers V8 engine bindings for other programming languages.
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be parsed and evaluated in a V8 context.
:::note pass
This section describes a flow where the script is parsed and evaluated every
time the program is run.
Using V8 snapshots, SheetJS libraries can be parsed and evaluated beforehand.
This greatly improves program startup time.
The ["Snapshots"](#snapshots) section includes a complete example.
:::
### Initialize V8
The official V8 `hello-world` example covers initialization and cleanup. For the
@ -890,7 +902,7 @@ Pulling data from an `ArrayBuffer` back into Rust involves an unsafe operation:
```rust
/* assuming JS code returns an ArrayBuffer, copy result to a Vec<u8> */
fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec<u8> {
let source = v8::String::new(scope, &code).unwrap();
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result: v8::Local<v8::ArrayBuffer> = script.run(scope).unwrap().try_into().unwrap();
/* In C++, `Data` returns a pointer. Collecting data into Vec<u8> is unsafe */
@ -907,7 +919,7 @@ This demo was last tested in the following deployments:
| Architecture | V8 Crate | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `0.89.0` | 2024-04-04 |
| `darwin-x64` | `0.92.0` | 2024-05-28 |
| `darwin-arm` | `0.92.0` | 2024-05-25 |
| `win10-x64` | `0.89.0` | 2024-03-24 |
| `linux-x64` | `0.91.0` | 2024-04-25 |
@ -957,3 +969,125 @@ cargo run pres.numbers
If the program succeeded, the CSV contents will be printed to console and the
file `sheetjsw.xlsb` will be created. That file can be opened with Excel.
## Snapshots
At a high level, V8 snapshots are raw dumps of the V8 engine state. It is much
more efficient for programs to load snapshots than to evaluate code.
### Snapshot Demo
There are two parts to this demo:
A) The [`snapshot`](pathname:///cli/snapshot.rs) command creates a snapshot with
the [SheetJS standalone script](/docs/getting-started/installation/standalone)
and [supplementary NUMBERS script](/docs/api/write-options#writing-options). It
will dump the snapshot to `snapshot.bin`
B) The [`sheet2csv`](pathname:///cli/sheet2csv.rs) tool embeds `snapshot.bin`.
The tool will parse a specified file, print CSV contents of a named worksheet,
and export the workbook to NUMBERS.
:::note Tested Deployments
This demo was last tested in the following deployments:
| Architecture | V8 Version | Crate | Date |
|:-------------|:--------------|:---------|:-----------|
| `darwin-x64` | `12.6.228.3` | `0.92.0` | 2024-05-28 |
| `darwin-arm` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `win10-x64` | `12.3.219.9` | `0.88.0` | 2024-03-24 |
| `win11-x64` | `12.6.228.3` | `0.92.0` | 2024-05-23 |
| `linux-x64` | `12.3.219.9` | `0.88.0` | 2024-03-18 |
| `linux-arm` | `12.6.228.3` | `0.92.0` | 2024-05-26 |
:::
0) Make a new folder for the project:
```bash
mkdir sheetjs2csv
cd sheetjs2csv
```
1) Download the following scripts:
- [`Cargo.toml`](pathname:///cli/Cargo.toml)
- [`snapshot.rs`](pathname:///cli/snapshot.rs)
- [`sheet2csv.rs`](pathname:///cli/sheet2csv.rs)
```bash
curl -o Cargo.toml https://docs.sheetjs.com/cli/Cargo.toml
curl -o snapshot.rs https://docs.sheetjs.com/cli/snapshot.rs
curl -o sheet2csv.rs https://docs.sheetjs.com/cli/sheet2csv.rs
```
2) Download the SheetJS Standalone script and NUMBERS supplementary script. Move
both scripts to the project directory:
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.zahl.js`}>xlsx.zahl.js</a></li>
</ul>
<CodeBlock language="bash">{`\
curl -o xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -o xlsx.zahl.js https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.zahl.js`}
</CodeBlock>
3) Build the V8 snapshot:
```bash
cargo build --bin snapshot
cargo run --bin snapshot
```
:::caution pass
In some tests, 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>()'
```
Versions `0.75.1`, `0.82.0`, and `0.92.0` are known to work.
:::
4) Build `sheet2csv` (`sheet2csv.exe` in Windows):
```bash
cargo build --release --bin sheet2csv
```
5) Download the test file https://docs.sheetjs.com/pres.numbers:
```bash
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
```
6) Test the application:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```bash
mv target/release/sheet2csv .
./sheet2csv pres.numbers
```
</TabItem>
<TabItem value="win" label="Windows">
```bash
mv target/release/sheet2csv.exe .
.\sheet2csv.exe pres.numbers
```
</TabItem>
</Tabs>

@ -1,16 +1,24 @@
/* run code, get result as a Rust String */
fn eval_code(scope: &mut v8::HandleScope, code: &str) -> std::string::String {
let source = v8::String::new(scope, &code).unwrap();
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result = script.run(scope).unwrap();
return result.to_string(scope).unwrap().to_rust_string_lossy(scope);
}
/* assuming JS code returns an ArrayBuffer, copy result to a Vec<u8> */
fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec<u8> {
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result: v8::Local<v8::ArrayBuffer> = script.run(scope).unwrap().try_into().unwrap();
unsafe { return std::slice::from_raw_parts_mut(result.data().unwrap().cast::<u8>().as_ptr(), result.byte_length()).to_vec(); }
}
fn main() {
/* parse arguments */
let mut iter = std::env::args();
let path: String = iter.nth(1).expect("must specify a file name");
let sheetname: String = match iter.nth(0) {
let sheetname: String = match iter.next() {
Some(v) => format!("'{}'", v),
None => "wb.SheetNames[0]".to_string()
};
@ -29,14 +37,24 @@ fn main() {
let context_scope = &mut v8::ContextScope::new(handle_scope, context);
/* read file */
let data: Vec<u8> = std::fs::read(path.clone()).unwrap();
let back: v8::UniqueRef<v8::BackingStore> = v8::ArrayBuffer::new_backing_store_from_vec(data);
let shared = back.make_shared();
let ab: v8::Local<v8::ArrayBuffer> = v8::ArrayBuffer::with_backing_store(context_scope, &shared);
let key = v8::String::new(context_scope, "buf").unwrap();
context.global(context_scope).set(context_scope, key.into(), ab.into());
{
let data: Vec<u8> = std::fs::read(path.clone()).unwrap();
let back: v8::UniqueRef<v8::BackingStore> = v8::ArrayBuffer::new_backing_store_from_vec(data);
let shared = back.make_shared();
let ab: v8::Local<v8::ArrayBuffer> = v8::ArrayBuffer::with_backing_store(context_scope, &shared);
let key = v8::String::new(context_scope, "buf").unwrap();
context.global(context_scope).set(context_scope, key.into(), ab.into());
}
/* print CSV of specified sheet */
let result = eval_code(context_scope, &mut format!("var wb = XLSX.read(buf, {{dense: true}}); XLSX.utils.sheet_to_csv(wb.Sheets[{}])", sheetname));
println!("{}", result);
{
let result = eval_code(context_scope, &format!("var wb = XLSX.read(buf, {{dense: true}}); XLSX.utils.sheet_to_csv(wb.Sheets[{}])", sheetname));
println!("{}", result);
}
/* write sheetjsw.numbers */
{
let result = eval_code_ab(context_scope, "XLSX.write(wb, {type:'array', bookType:'numbers', numbers: XLSX_ZAHL_PAYLOAD})");
std::fs::write("sheetjsw.numbers", result).unwrap();
}
}

@ -1,38 +1,42 @@
/* run code, get result as a Rust String */
fn eval_code(scope: &mut v8::HandleScope, code: &str) -> std::string::String {
let source = v8::String::new(scope, &code).unwrap();
/*! sheetjs (C) SheetJS -- https://sheetjs.com */
/* run code and ignore result */
fn eval_code(scope: &mut v8::HandleScope, code: &str) {
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result = script.run(scope).unwrap();
return result.to_string(scope).unwrap().to_rust_string_lossy(scope);
let _ = script.run(scope);
}
fn main() {
create_snapshot();
}
fn create_snapshot() {
/* initialize */
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
v8::V8::initialize();
let startup_data = {
let mut isolate = v8::Isolate::snapshot_creator(None);
{
let handle_scope = &mut v8::HandleScope::new(&mut isolate);
let context = v8::Context::new(handle_scope);
let context_scope = &mut v8::ContextScope::new(handle_scope, context);
/* use SnapshotCreator */
let mut isolate = v8::Isolate::snapshot_creator(None);
/* load library */
{
let script = std::fs::read_to_string("./xlsx.full.min.js").expect("Error reading xlsx.full.min.js");
let _result = eval_code(context_scope, &script);
}
context_scope.set_default_context(context);
/* scope enforces the lifetime of the `&mut isolate` in `handle_scope` */
{
/* same steps as normal flow */
let handle_scope = &mut v8::HandleScope::new(&mut isolate);
let context = v8::Context::new(handle_scope);
let context_scope = &mut v8::ContextScope::new(handle_scope, context);
/* instructs the snapshot creator to dump the new context */
context_scope.set_default_context(context);
/* load scripts */
let scripts = vec!["./xlsx.full.min.js", "./xlsx.zahl.js"];
for path in &scripts {
let script = std::fs::read_to_string(path).unwrap_or_else(|_| panic!("Error reading {}", path));
eval_code(context_scope, &script);
}
isolate.create_blob(v8::FunctionCodeHandling::Clear).unwrap()
};
/* create snapshot */
let startup_data = isolate.create_blob(v8::FunctionCodeHandling::Clear).unwrap();
/* write to snapshot.bin */
let blob: Vec<u8> = startup_data.to_vec();
std::fs::write("snapshot.bin", blob).unwrap();
}

@ -1,7 +1,7 @@
/*! sheetjs (C) SheetJS -- https://sheetjs.com */
/* run code, get result as a Rust String */
fn eval_code(scope: &mut v8::HandleScope, code: &str) -> std::string::String {
let source = v8::String::new(scope, &code).unwrap();
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result = script.run(scope).unwrap();
return result.to_string(scope).unwrap().to_rust_string_lossy(scope);
@ -9,13 +9,17 @@ fn eval_code(scope: &mut v8::HandleScope, code: &str) -> std::string::String {
/* assuming JS code returns an ArrayBuffer, copy result to a Vec<u8> */
fn eval_code_ab(scope: &mut v8::HandleScope, code: &str) -> Vec<u8> {
let source = v8::String::new(scope, &code).unwrap();
let source = v8::String::new(scope, code).unwrap();
let script = v8::Script::compile(scope, source, None).unwrap();
let result: v8::Local<v8::ArrayBuffer> = script.run(scope).unwrap().try_into().unwrap();
unsafe { return std::slice::from_raw_parts_mut(result.data().unwrap().cast::<u8>().as_ptr(), result.byte_length()).to_vec(); }
}
fn main() {
/* parse arguments */
let mut iter = std::env::args();
let path: String = iter.nth(1).expect("must specify a file name");
/* initialize */
let platform = v8::new_default_platform(0, false).make_shared();
v8::V8::initialize_platform(platform);
@ -40,7 +44,6 @@ fn main() {
/* read file */
{
let path: String = std::env::args().collect::<Vec<_>>().into_iter().nth(1).unwrap().to_string();
let data: Vec<u8> = std::fs::read(path.clone()).unwrap();
let back: v8::UniqueRef<v8::BackingStore> = v8::ArrayBuffer::new_backing_store_from_vec(data);
let shared = back.make_shared();

18
tests/cli-boxednode.sh Executable file

@ -0,0 +1,18 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/boxednode
cd /tmp
rm -rf sheetjs-boxednode
mkdir sheetjs-boxednode
cd sheetjs-boxednode
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz exit-on-epipe commander@2
## NOTE: these steps are for darwin-x64
npx boxednode@2.4.3 -s xlsx-cli.js -t xlsx-cli
./xlsx-cli pres.numbers

35
tests/cli-bunsea.sh Executable file

@ -0,0 +1,35 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/bunsea
cd /tmp
rm -rf sheetjs-bunsea
mkdir sheetjs-bunsea
cd sheetjs-bunsea
bun --version
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
cat >sheet2csv.ts <<EOF
const XLSX = require("xlsx");
/* process.argv[2] is the first argument to the script */
const filename = process.argv[2];
/* read file */
const wb = XLSX.readFile(filename);
/* generate CSV of first sheet */
const ws = wb.Sheets[wb.SheetNames[0]];
const csv = XLSX.utils.sheet_to_csv(ws);
/* print to terminal */
console.log(csv);
EOF
bun install https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz
bun run sheet2csv.ts pres.numbers
bun build ./sheet2csv.ts --compile --outfile sheet2csv
./sheet2csv pres.numbers

16
tests/cli-denosea.sh Executable file

@ -0,0 +1,16 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/denosea
cd /tmp
rm -rf sheetjs-cli-deno
mkdir -p sheetjs-cli-deno
cd sheetjs-cli-deno
deno --version
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
deno run -r --allow-read https://docs.sheetjs.com/cli/sheet2csv.ts pres.numbers
deno compile -r --allow-read https://docs.sheetjs.com/cli/sheet2csv.ts
./sheet2csv pres.numbers

18
tests/cli-nexe.sh Executable file

@ -0,0 +1,18 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/nexe
cd /tmp
rm -rf sheetjs-nexe
mkdir sheetjs-nexe
cd sheetjs-nexe
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz exit-on-epipe commander@2
## NOTE: these steps are for darwin-x64
npx nexe -t 14.15.3 xlsx-cli.js
./xlsx-cli pres.numbers

65
tests/cli-nodesea.sh Executable file

@ -0,0 +1,65 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/nodesea
cd /tmp
rm -rf sheetjs-sea
mkdir sheetjs-sea
cd sheetjs-sea
node --version
npm init -y
cat >sheet2csv.js <<EOF
// For NodeJS SEA, the CommonJS \`require\` must be used
const { createRequire } = require('node:module');
require = createRequire(__filename);
const { readFile, utils } = require("xlsx");
// argv[2] is the first argument to the script
const filename = process.argv[2];
// read file
const wb = readFile(filename);
// generate CSV of first sheet
const ws = wb.Sheets[wb.SheetNames[0]];
const csv = utils.sheet_to_csv(ws);
// print to terminal
console.log(csv);
EOF
npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz
### Script Test
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
node sheet2csv.js pres.numbers
### SEA Bundle
cat >sheet2csv.json <<EOF
{
"main": "sheet2csv.js",
"output": "sheet2csv.blob"
}
EOF
node --experimental-sea-config sheet2csv.json
## NOTE: these steps are for darwin-x64
cp `which node` sheet2csv
codesign --remove-signature ./sheet2csv
npx -y postject --sentinel-fuse NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2 --macho-segment-name NODE_SEA sheet2csv NODE_SEA_BLOB sheet2csv.blob
codesign -s - ./sheet2csv
./sheet2csv pres.numbers
codesign -dv ./sheet2csv

20
tests/cli-pkg.sh Executable file

@ -0,0 +1,20 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/cli/pkg
cd /tmp
rm -rf sheetjs-pkg
mkdir sheetjs-pkg
cd sheetjs-pkg
curl -o pres.numbers https://docs.sheetjs.com/pres.numbers
curl -o xlsx-cli.js https://docs.sheetjs.com/cli/xlsx-cli.js
npm i --save https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz exit-on-epipe commander@2
## NOTE: must downgrade to node 18
npx pkg xlsx-cli.js
## NOTE: these steps are for darwin-x64
./xlsx-cli-macos pres.numbers