Demo refresh

This commit is contained in:
SheetJS 2025-03-30 22:09:31 -04:00
parent 50c4139bb4
commit 19b9f5b122
31 changed files with 474 additions and 234 deletions

@ -292,8 +292,8 @@
<Cell><Data ss:Type="String">Python</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"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>

@ -122,7 +122,7 @@ This demo was last tested in the following deployments:
| Architecture | BunJS | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `1.1.39` | 2024-12-17 |
| `darwin-arm` | `1.2.2` | 2025-02-16 |
| `darwin-arm` | `1.2.7` | 2025-03-30 |
| `win11-x64` | `1.1.42` | 2024-12-22 |
| `win11-arm` | `1.2.3` | 2025-02-23 |
| `linux-x64` | `1.1.40` | 2024-12-19 |

@ -40,8 +40,8 @@ This browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
| Chrome 126 | 2024-06-21 |
| Safari 17.4 | 2024-06-20 |
| Chrome 133 | 2025-03-30 |
| Safari 18.3 | 2025-03-30 |
:::

@ -41,7 +41,7 @@ This demo was tested in the following deployments:
| Architecture | JS Engine | Pandas | Python | Date |
|:-------------|:----------------|:-------|:-------|:-----------|
| `darwin-x64` | Duktape `2.7.0` | 2.2.3 | 3.13.1 | 2024-12-31 |
| `darwin-arm` | Duktape `2.7.0` | 2.2.2 | 3.12.3 | 2024-06-30 |
| `darwin-arm` | Duktape `2.7.0` | 2.2.3 | 3.13.2 | 2025-03-30 |
| `win11-x64` | Duktape `2.7.0` | 2.2.3 | 3.11.8 | 2024-12-21 |
| `win11-arm` | Duktape `2.7.0` | 2.2.3 | 3.13.2 | 2025-02-23 |
| `linux-x64` | Duktape `2.7.0` | 1.5.3 | 3.11.7 | 2025-01-01 |
@ -528,7 +528,7 @@ This demo was tested in the following deployments:
| Architecture | JS Engine | Polars | Python | Date |
|:-------------|:----------------|:--------|:-------|:-----------|
| `darwin-x64` | Duktape `2.7.0` | 1.18.0 | 3.13.1 | 2024-12-31 |
| `darwin-arm` | Duktape `2.7.0` | 0.20.31 | 3.12.3 | 2024-06-30 |
| `darwin-arm` | Duktape `2.7.0` | 1.26.0 | 3.13.2 | 2025-03-30 |
| `win11-x64` | Duktape `2.7.0` | 1.17.1 | 3.11.8 | 2024-12-21 |
| `win11-arm` | Duktape `2.7.0` | 1.23.0 | 3.13.2 | 2025-02-23 |
| `linux-x64` | Duktape `2.7.0` | 1.18.0 | 3.11.7 | 2025-01-01 |

@ -128,9 +128,9 @@ function exportFile() {
<td>{p.Index}</td>
</tr>{/each}
<!-- highlight-end -->
</tbody><tfoot><td colSpan={2}>
</tbody><tfoot><tr><td colSpan={2}>
<button on:click={exportFile}>Export XLSX</button>
</td></tfoot></table>
</td></tfoot></tr></table>
</main>
```
@ -143,7 +143,7 @@ This demo was tested in the following environments:
| SvelteJS | ViteJS | Date |
|:---------|:---------|:-----------|
| `4.2.18` | `5.2.13` | 2024-06-07 |
| `5.25.3` | `6.2.3` | 2025-03-30 |
:::
@ -170,7 +170,9 @@ The page will refresh and show a table with an Export button. Click the button
and the page will attempt to download `SheetJSSvelteAoA.xlsx`. There may be a
delay since Vite will try to optimize the SheetJS library on the fly.
5) Build the site:
5) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
6) Build the site:
```bash
npm run build
@ -178,10 +180,10 @@ npm run build
The generated site will be placed in the `dist` folder.
6) Start a local web server:
7) Start a local web server:
```bash
npx http-server dist
npx -y http-server dist
```
Access the displayed URL (typically `http://localhost:8080`) with a web browser
@ -243,7 +245,7 @@ This demo was tested in the following environments:
| SvelteJS | ViteJS | Date |
|:---------|:---------|:-----------|
| `4.2.18` | `5.2.13` | 2024-06-07 |
| `5.25.3` | `6.2.3` | 2025-03-30 |
:::
@ -270,7 +272,9 @@ The page will refresh and show a table with an Export button. Click the button
and the page will attempt to download `SheetJSSvelteHTML.xlsx`. There may be a
delay since Vite will try to optimize the SheetJS library on the fly.
5) Build the site:
5) Stop the server (press <kbd>CTRL</kbd>+<kbd>C</kbd> in the terminal window).
6) Build the site:
```bash
npm run build
@ -278,10 +282,10 @@ npm run build
The generated site will be placed in the `dist` folder.
6) Start a local web server:
7) Start a local web server:
```bash
npx http-server dist
npx -y http-server dist
```
Access the displayed URL (typically `http://localhost:8080`) with a web browser

@ -36,8 +36,8 @@ This demo was tested in the following environments:
| Browser | Version | Date |
|:-------------|:------------------|:-----------|
| Chromium 125 | `1.8.2` (latest) | 2024-06-09 |
| Chromium 125 | `1.2.32` (legacy) | 2024-06-09 |
| Chromium 133 | `1.8.2` (latest) | 2025-03-30 |
| Chromium 133 | `1.2.32` (legacy) | 2025-03-30 |
:::
@ -288,8 +288,13 @@ app.controller('sheetjs', function($scope, $http) {
</html>`}
</CodeBlock>
2) Start a local web server with `npx http-server .` and access the displayed
URL with a web browser (typically `http://localhost:8080`)
2) Start a local web server:
```bash
npx -y http-server .
```
Access the displayed URL with a web browser (typically `http://localhost:8080`)
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
store an array of objects in state. When the "Export Table" button is clicked,
@ -387,8 +392,13 @@ app.controller('sheetjs', function($scope, $http) {
</html>`}
</CodeBlock>
2) Start a local web server with `npx http-server .` and access the displayed
URL with a web browser (typically `http://localhost:8080`)
2) Start a local web server:
```bash
npx -y http-server .
```
Access the displayed URL with a web browser (typically `http://localhost:8080`)
When the page loads, the app will fetch https://docs.sheetjs.com/pres.xlsx and
store the HTML string in state. When the "Export Table" button is clicked, a

@ -76,7 +76,7 @@ This demo was tested in the following environments:
| Platform | Date |
|:-------------|:-----------|
| Chromium 125 | 2024-06-08 |
| Chromium 133 | 2025-03-30 |
Demos exclusively using Dojo Core were tested using Dojo Toolkit `1.17.3`.

@ -41,9 +41,10 @@ This demo was tested in the following environments:
| ViteJS | Date |
|:---------|:-----------|
| `5.4.10` | 2024-11-04 |
| `4.5.5` | 2024-11-04 |
| `3.2.11` | 2024-11-04 |
| `6.2.3` | 2025-03-30 |
| `5.4.15` | 2025-03-30 |
| `4.5.10` | 2025-03-30 |
| `3.2.11` | 2025-03-30 |
:::

@ -90,8 +90,8 @@ Each browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
| Chrome 126 | 2024-06-19 |
| Safari 17.3 | 2024-06-19 |
| Chrome 133 | 2025-03-30 |
| Safari 18.3 | 2025-03-30 |
:::
@ -411,9 +411,9 @@ This demo was tested in the following environments:
| `12.22.12` | 2024-06-21 | |
| `14.21.3` | 2024-06-21 | |
| `16.20.2` | 2024-06-21 | |
| `18.20.3` | 2024-06-21 | |
| `20.15.0` | 2024-06-21 | |
| `22.3.0` | 2024-06-21 | |
| `18.20.8` | 2025-03-30 | |
| `20.18.0` | 2025-03-30 | |
| `22.14.0` | 2025-03-30 | |
The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`:
@ -484,9 +484,9 @@ This demo was tested in the following environments:
| NodeJS | Date |
|:-----------|:-----------|
| `18.20.3` | 2024-06-21 |
| `20.15.0` | 2024-06-21 |
| `22.3.0` | 2024-06-21 |
| `18.20.8` | 2025-03-30 |
| `20.18.0` | 2025-03-30 |
| `22.14.0` | 2025-03-30 |
:::
@ -579,9 +579,9 @@ This demo was tested in the following environments:
| `12.22.12` | 2024-06-21 | |
| `14.21.3` | 2024-06-21 | |
| `16.20.2` | 2024-06-21 | |
| `18.20.3` | 2024-06-21 | |
| `20.15.0` | 2024-06-21 | |
| `22.3.0` | 2024-06-21 | |
| `18.20.8` | 2025-03-30 | |
| `20.18.0` | 2025-03-30 | |
| `22.14.0` | 2025-03-30 | |
The `NODE_TLS_REJECT_UNAUTHORIZED` workaround sets the value to `'0'`:
@ -651,9 +651,9 @@ This demo was tested in the following environments:
| `12.22.12` | 1.7.2 | 2024-06-21 |
| `14.21.3` | 1.7.2 | 2024-06-21 |
| `16.20.2` | 1.7.2 | 2024-06-21 |
| `18.20.3` | 1.7.2 | 2024-06-21 |
| `20.15.0` | 1.7.2 | 2024-06-21 |
| `22.3.0` | 1.7.2 | 2024-06-21 |
| `18.20.8` | 1.8.4 | 2025-03-30 |
| `20.18.0` | 1.8.4 | 2025-03-30 |
| `22.14.0` | 1.8.4 | 2025-03-30 |
:::
@ -663,7 +663,7 @@ This demo was tested in the following environments:
1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz axios@1.7.2`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz axios@1.8.4`}
</CodeBlock>
2) Save the following to `SheetJSAxios.js`:

@ -135,8 +135,8 @@ Each browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
| Chrome 126 | 2024-06-19 |
| Safari 17.3 | 2024-06-19 |
| Chrome 133 | 2025-03-30 |
| Safari 18.3 | 2025-03-30 |
:::

@ -169,7 +169,7 @@ export default defineConfig({
plugins: [
{ // this plugin handles ?sheetjs tags
name: "vite-sheet",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?sheetjs$/)) return;
var wb = read(readFileSync(id.replace(/\?sheetjs$/, "")));
var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
@ -243,7 +243,7 @@ export default defineConfig({
plugins: [
{ // this plugin handles ?html tags
name: "vite-sheet-html",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?html/)) return;
var wb = read(readFileSync(id.replace(/\?html/, "")));
var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
@ -309,7 +309,7 @@ export default defineConfig({
plugins: [
{ // this plugin handles ?b64 tags
name: "vite-b64-plugin",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?b64$/)) return;
var path = id.replace(/\?b64/, "");
var data = readFileSync(path, "base64");
@ -356,10 +356,11 @@ This demo was tested in the following environments:
| ViteJS | Date |
|:---------|:-----------|
| `5.2.12` | 2024-06-02 |
| `4.5.3` | 2024-06-02 |
| `3.2.10` | 2024-06-02 |
| `2.9.18` | 2024-06-02 |
| `6.2.3` | 2025-03-30 |
| `5.4.15` | 2025-03-30 |
| `4.5.10` | 2025-03-30 |
| `3.2.11` | 2025-03-30 |
| `2.9.18` | 2025-03-30 |
:::

@ -53,15 +53,15 @@ This demo was tested in the following environments:
| OS | Device | Config | Date |
|:-----------|:--------------------|:-------|:-----------|
| Android 30 | NVIDIA Shield | A | 2024-05-30 |
| iOS 15.1 | iPad Pro | A | 2024-05-30 |
| Android 34 | NVIDIA Shield | B | 2025-03-30 |
| iOS 15.6 | iPhone 13 Pro Max | B | 2025-03-30 |
**Simulators**
| OS | Device | Config | Dev Platform | Date |
|:-----------|:--------------------|:-------|:-------------|:-----------|
| Android 34 | Pixel 3a | A | `darwin-arm` | 2024-05-30 |
| iOS 17.5 | iPhone SE (3rd gen) | A | `darwin-arm` | 2024-05-30 |
| Android 34 | Pixel 3a | B | `darwin-arm` | 2025-03-30 |
| iOS 18.2 | iPhone SE (3rd gen) | B | `darwin-arm` | 2025-03-30 |
<details>
<summary><b>Configurations</b> (click to show)</summary>
@ -72,6 +72,12 @@ Configuration A:
- Cordova: `cordova-lib@12.0.1`, `android 13.0.0, ios 7.1.0`
- File Integration: `@awesome-cordova-plugins/file` version `6.7.0`
Configuration B:
- Ionic: `@ionic/angular 8.5.2`, `@ionic/angular-toolkit 12.1.1`
- Cordova: `cordova-lib@12.0.2`, `android 14.0.0, ios 7.1.1`
- File Integration: `@awesome-cordova-plugins/file` version `6.16.0`
</details>
:::
@ -81,15 +87,15 @@ Configuration A:
Before starting this demo, manually disable telemetry:
```bash
npx @ionic/cli config set -g telemetry false
npx @capacitor/cli telemetry off
npx -y @ionic/cli config set -g telemetry false
npx -y @capacitor/cli telemetry off
```
To verify telemetry was disabled:
```bash
npx @ionic/cli config get -g telemetry
npx @capacitor/cli telemetry
npx -y @ionic/cli config get -g telemetry
npx -y @capacitor/cli telemetry
```
:::
@ -223,7 +229,12 @@ known location. After writing, an alert will display the location of the file.
### Platform Setup
0) Disable telemetry as noted in the warning.
0) Disable telemetry:
```bash
npx -y @ionic/cli config set -g telemetry false
npx -y @capacitor/cli telemetry off
```
1) Follow the official instructions for iOS and Android development[^9].
@ -262,7 +273,7 @@ When asked to select `NgModules` or `Standalone Components`, select `NgModules`
If a prompt asks to confirm Cordova use, enter <kbd>Y</kbd> to continue.
If a prompt asks about creating an Ionic account, enter <kbd>N</kbd> to opt out.
If a prompt asks to create an Ionic account, enter <kbd>N</kbd> to opt out.
:::caution pass
@ -284,28 +295,9 @@ cd ..
```bash
cd SheetJSIonic
ionic cordova plugin add cordova-plugin-file
ionic cordova platform add android --confirm
ionic cordova platform add ios --confirm
npm i --save @awesome-cordova-plugins/core @awesome-cordova-plugins/file @ionic/cordova-builders
```
:::note pass
If `cordova-plugin-file` is added before the platforms, installation may fail:
```
CordovaError: Could not load API for ios project
```
This can be resolved by removing and reinstalling the `ios` platform:
```bash
ionic cordova platform rm ios
ionic cordova platform add ios --confirm
```
:::
:::caution pass
If the `npm i` step fails due to `rxjs` resolution, add the highlighted lines
@ -375,10 +367,144 @@ curl.exe -o src/app/home/home.page.ts -L https://docs.sheetjs.com/ionic/home.pag
:::
### Android
8) Add the Android platform to the project:
```bash
ionic cordova platform add android --confirm
npm i --save cordova-android
```
9) Enable file reading and writing in the Android app.
Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following
two lines before the `application` tag:
```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)"
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
```
In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`.
10) Build the app and start the emulator:
```bash
ionic cordova emulate android
```
When the app is loaded, a list of Presidents should be displayed. This list is
dynamically generated by fetching and parsing a test file.
:::caution pass
In some test runs, `cordova build android --emulator` step failed with error:
```
Could not find or parse valid build output file
```
This was resolved by forcefully installing `cordova-android`:
```bash
npm i --save cordova-android
```
:::
:::caution pass
In some test runs, Ionic could not find the emulator:
```
ERR_NO_TARGET: No target devices/emulators available.
```
The target emulator can be found by running
```bash
avdmanager list avd
```
In a test run, the output showed a Pixel 3a with the following details:
```text
// highlight-next-line
Name: Pixel_3a_API_34
Device: pixel_3a (Google)
Path: /Users/SheetJS/.android/avd/Pixel_4_API_33.avd
```
The Ionic command accepts a `--target` flag. Pass the emulator name:
```bash
ionic cordova emulate android --target=Pixel_3a_API_34
```
:::
:::caution pass
In some tests, the build failed with a Gradle error:
```
Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle
in your path or install Android Studio
```
On macOS, this issue was resolved by installing Gradle with Homebrew manager:
```bash
brew install gradle
```
:::
:::danger pass
When the demo was last tested on Android, reading files worked as expected.
However, the generated files were not externally visible from the Files app.
**This is a known bug with Android SDK 33 and the underlying file plugins!**
:::
### iOS
8) Enable file sharing and make the documents folder visible in the iOS app.
:::danger pass
**iOS testing can only be performed on Apple hardware running macOS!**
Xcode and iOS simulators are not available on Windows or Linux.
:::
11) Add the iOS platform to the project:
```bash
ionic cordova platform add ios --confirm
```
:::note pass
If `cordova-plugin-file` is added before the platforms, installation may fail:
```
CordovaError: Could not load API for ios project
```
This can be resolved by removing and reinstalling the `ios` platform:
```bash
ionic cordova platform rm ios
ionic cordova platform add ios --confirm
```
:::
12) Enable file sharing and make the documents folder visible in the iOS app.
Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`:
```xml title="platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist (add to file)"
@ -395,7 +521,7 @@ Add the following lines to `platforms/ios/SheetJSIonic/SheetJSIonic-Info.plist`:
(The root element of the document is `plist` and it contains one `dict` child)
9) Build the app and start the simulator
13) Build the app and start the simulator
```bash
ionic cordova emulate ios
@ -464,71 +590,86 @@ ng add @ionic/cordova-builders
:::
### Android
### iOS Device
10) Enable file reading and writing in the Android app.
14) Connect an iOS device to the computer and "Trust" the device if prompted.
Edit `platforms/android/app/src/main/AndroidManifest.xml` and add the following
two lines before the `application` tag:
15) Enable code signing for the project:
```xml title="platforms/android/app/src/main/AndroidManifest.xml (add to file)"
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
```
In the `application` tag, add the attribute `android:requestLegacyExternalStorage="true"`.
11) Build the app and start the emulator
Open the `SheetJSIonic.xcodeproj` project in Xcode:
```bash
ionic cordova emulate android
open platforms/ios/SheetJSIonic.xcodeproj
```
When the app is loaded, a list of Presidents should be displayed. This list is
dynamically generated by fetching and parsing a test file.
Select the "SheetJSIonic" project in the "Project navigator" side panel.
:::caution pass
In the main panel, select "Signing & Capabilities".
In some test runs, `cordova build android --emulator` step failed with error:
In the "Team" dropdown, select a certificate.
```
Could not find or parse valid build output file
```
In the "Bundle Identifier" text box, enter `com.sheetjs.SheetJSIonic`
This was resolved by forcefully installing `cordova-android`:
16) Launch the app on the device:
```bash
npm i --save cordova-android
ionic cordova run ios --device --verbose
```
:::info pass
In the most recent test, the `native-run ios` command failed with
```
[native-run] ERR_UNKNOWN: Path 'platforms/ios/build/device/SheetJSIonic.ipa' not found
```
Inspecting `platforms/ios/build/`, the actual folder name was:
```bash
% ls platforms/ios/build
#highlight-next-line
Debug-iphoneos
```
To force `native-run` to use the device, the name must be found by inspecting
the output of `native-run ios --list`:
```bash
% native-run ios --list
Connected Devices:
Name API Target ID
---------------------------------------------
SheetJS iOS 15.6 12345678-90ABCDEF12345678
```
`native-run` accepts a `--device` flag. Pass the device name:
```bash
native-run ios --app platforms/ios/build/Debug-iphoneos/SheetJSIonic.ipa --device SheetJS
```
:::
:::caution pass
17) Test the app.
In some tests, the build failed with a Gradle error:
The app will fetch a file and display the contents in a table.
```
Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle
in your path or install Android Studio
```
Tap "Export Data" to create a file. To find the file, switch to the "Files" app
and browse "On My iPhone" > "SheetJSIonic". There should be a new spreadsheet
named "SheetJSIonic".
On macOS, this issue was resolved by installing Gradle with Homebrew manager:
Switch to the "Numbers" app and open that file. Tap "EDIT" to make changes.
Change cell A7 to "SheetJS Dev" and cell B7 to 47. Tap "Done" and close the app.
```bash
brew install gradle
```
:::
:::danger pass
When the demo was last tested on Android, reading files worked as expected.
However, the generated files were not externally visible from the Files app.
**This is a known bug with Android SDK 33 and the underlying file plugins!**
:::
Switch back to "SheetJSIonic" and tap "Import Data". Tap "Choose Files" in the
popup. Tap "Browse" in the bottom of the sheet. Navigate to "On My iPhone" >
"SheetJSIonic" and tap the new "SheetJSIonic" spreadsheet. The screen will show
the file with the new line.
[^1]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays)
[^2]: See [`ion-grid`](https://ionicframework.com/docs/api/grid) in the Ionic documentation.

@ -53,8 +53,8 @@ This demo was tested in the following environments:
|:-----------|:--------------------|:------------------|:-------------|:-----------|
| Android 35 | Pixel 9 Pro | `6.2.0` / `6.0.3` | `darwin-x64` | 2025-01-19 |
| iOS 18.2 | iPhone 16 Pro Max | `6.2.0` / `6.0.3` | `darwin-x64` | 2025-01-19 |
| Android 34 | Pixel 3a | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
| iOS 17.5 | iPhone 15 Pro Max | `6.0.0` / `6.0.0` | `darwin-arm` | 2024-06-02 |
| Android 34 | Pixel 3a | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 |
| iOS 18.2 | iPhone 16 Pro Max | `7.1.0` / `7.0.0` | `darwin-arm` | 2025-03-30 |
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `win11-x64` | 2024-12-21 |
| Android 35 | Pixel 9 | `6.2.0` / `6.0.2` | `linux-x64` | 2025-01-02 |
@ -438,9 +438,8 @@ picker for saving the file. Select the `sheetjs-cap` folder and tap "Save". If
prompted to "Replace Existing Items?", tap "Replace".
Switch back to the app and tap "Choose File". Tap "Choose File" in the popup.
Tap on "Choose File" in the app and "Choose File" in the popup. In the picker,
tap "Recents" and select the newest `SheetJSCap` file. The table will refresh.
In the picker, tap "Recents" and select the newest `SheetJSCap` file. The table
will refresh with the new data.
### Android Device

@ -208,7 +208,7 @@ This demo was tested in the following environments:
| OS and Version | Architecture | Electron | Date |
|:---------------|:-------------|:---------|:-----------|
| macOS 15.2 | `darwin-x64` | `33.2.1` | 2024-12-31 |
| macOS 14.5 | `darwin-arm` | `30.0.8` | 2024-05-28 |
| macOS 14.5 | `darwin-arm` | `35.1.2` | 2025-03-38 |
| Windows 11 | `win11-x64` | `33.2.1` | 2025-02-11 |
| Windows 11 | `win11-arm` | `33.2.1` | 2025-02-23 |
| Linux (HoloOS) | `linux-x64` | `33.2.1` | 2025-01-02 |
@ -361,7 +361,7 @@ and select `pres.numbers`.
## Electron Breaking Changes
The first version of this demo used Electron `1.7.5`. The current demo includes
the required changes for Electron `33.2.1`.
the required changes for Electron `35.1.2`.
There are no Electron-specific workarounds in the library, but Electron broke
backwards compatibility multiple times. A summary of changes is noted below.

@ -122,7 +122,7 @@ This demo was tested in the following environments:
| OS and Version | Architecture | NW.js | Date | Notes |
|:---------------|:-------------|:---------|:-----------|:---------------------|
| macOS 15.2 | `darwin-x64` | `0.94.0` | 2024-12-31 | |
| macOS 14.5 | `darwin-arm` | `0.88.0` | 2024-05-28 | |
| macOS 14.5 | `darwin-arm` | `0.94.0` | 2025-03-30 | |
| Windows 11 | `win11-x64` | `0.94.0` | 2024-12-19 | |
| Windows 11 | `win11-arm` | `0.94.0` | 2025-02-23 | |
| Linux (HoloOS) | `linux-x64` | `0.89.0` | 2025-01-10 | |
@ -225,6 +225,7 @@ testing, version `4.11.6` correctly generated the standalone application.
| Architecture | Command |
|:-------------|:--------------------------------------------------------------|
| `darwin-x64` | `open ../out/sheetjs-nwjs.app` |
| `darwin-arm` | `open ../out/sheetjs-nwjs.app` |
| `win11-x64` | `..\out\sheetjs-nwjs.exe` |
| `win11-arm` | `..\out\sheetjs-nwjs.exe` |
| `linux-x64` | `../out/sheetjs-nwjs` |

@ -295,14 +295,14 @@ async function exportFile(table_element) {
This demo was tested in the following environments:
| OS and Version | Architecture | Wails | Date |
|:---------------|:-------------|:---------|:-----------|
| macOS 15.2 | `darwin-x64` | `v2.9.2` | 2024-12-31 |
| macOS 14.5 | `darwin-arm` | `v2.8.2` | 2024-05-28 |
| Windows 11 | `win11-x64` | `v2.9.2` | 2024-12-21 |
| Windows 11 | `win11-arm` | `v2.10` | 2025-02-23 |
| Linux (HoloOS) | `linux-x64` | `v2.9.2` | 2025-01-02 |
| Linux (Debian) | `linux-arm` | `v2.10` | 2025-02-16 |
| OS and Version | Architecture | Wails | Date |
|:---------------|:-------------|:----------|:-----------|
| macOS 15.2 | `darwin-x64` | `v2.9.2` | 2024-12-31 |
| macOS 14.5 | `darwin-arm` | `v2.10.1` | 2025-03-30 |
| Windows 11 | `win11-x64` | `v2.9.2` | 2024-12-21 |
| Windows 11 | `win11-arm` | `v2.10` | 2025-02-23 |
| Linux (HoloOS) | `linux-x64` | `v2.9.2` | 2025-01-02 |
| Linux (Debian) | `linux-arm` | `v2.10` | 2025-02-16 |
:::

@ -354,7 +354,7 @@ This demo was tested in the following environments:
| OS and Version | Architecture | Tauri | Date |
|:---------------|:-------------|:----------|:-----------|
| macOS 15.2 | `darwin-x64` | `v1.6.0` | 2024-12-31 |
| macOS 14.5 | `darwin-arm` | `v1.5.14` | 2024-05-26 |
| macOS 14.5 | `darwin-arm` | `v1.6.0` | 2025-03-30 |
| Windows 11 | `win11-x64` | `v1.6.0` | 2024-12-21 |
| Windows 11 | `win11-arm` | `v1.6.0` | 2025-02-23 |
| Linux (HoloOS) | `linux-x64` | `v1.6.0` | 2025-01-02 |
@ -384,16 +384,17 @@ If required dependencies are installed, the output will show a checkmark next to
<pre>
<span {...g}>[✔]</span> <span style={{...y.style,...B.style}}>Environment</span>
{` `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 15.2.0 x86_64 (X64)
{` `}<span {...c}>-</span> <span {...B}>OS</span>: Mac OS 14.5.0 arm64 (X64)
{` `}<span {...g}></span> <span {...B}>Xcode Command Line Tools</span>: installed
{` `}<span {...g}></span> <span {...B}>rustc</span>: 1.83.0 (90b35a623 2024-11-26)
{` `}<span {...g}></span> <span {...B}>cargo</span>: 1.83.0 (5ffbef321 2024-10-29)
{` `}<span {...g}></span> <span {...B}>rustup</span>: 1.27.1 (54dd3d00f 2024-04-24)
{` `}<span {...g}></span> <span {...B}>Rust toolchain</span>: stable-x86_64-apple-darwin (default)
{` `}<span {...g}></span> <span {...B}>rustc</span>: 1.85.1 (4eb161250 2025-03-15)
{` `}<span {...g}></span> <span {...B}>cargo</span>: 1.85.1 (d73d2caf9 2024-12-31)
{` `}<span {...g}></span> <span {...B}>rustup</span>: 1.28.1 (f9edccde0 2025-03-05)
{` `}<span {...g}></span> <span {...B}>Rust toolchain</span>: stable-aarch64-apple-darwin (default)
{` `}<span {...c}>-</span> <span {...B}>node</span>: 20.18.0
{` `}<span {...c}>-</span> <span {...B}>pnpm</span>: 9.12.3
{` `}<span {...c}>-</span> <span {...B}>npm</span>: 10.8.2
{` `}<span {...c}>-</span> <span {...B}>bun</span>: 1.1.42
{` `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.1.4
{` `}<span {...c}>-</span> <span {...B}>bun</span>: 1.2.7
{` `}<span {...c}>-</span> <span {...B}>deno</span>: deno 2.2.6
</pre>
:::caution pass
@ -536,7 +537,7 @@ export default defineConfig(async () => ({
- Replace `index.html` with the following codeblock:
```html title="index.html"
```html title="index.html (replace contents)"
<!doctype html>
<html lang="en">
<head>
@ -573,7 +574,7 @@ table.center {
- Replace `src/main.ts` with the following codeblock:
```ts title="src/main.ts"
```ts title="src/main.ts (replace contents)"
import { mount } from "kaioken";
import App from "./App";

@ -193,7 +193,7 @@ This demo was tested in the following environments:
| OS and Version | Architecture | Server | Client | Date |
|:---------------|:-------------|:---------|:---------|:-----------|
| macOS 15.2 | `darwin-x64` | `5.5.0` | `5.5.0` | 2024-12-31 |
| macOS 14.5 | `darwin-arm` | `5.1.0` | `5.1.0` | 2024-05-25 |
| macOS 14.5 | `darwin-arm` | `6.0.0` | `6.0.0` | 2025-03-30 |
| Windows 11 | `win11-x64` | `5.5.0` | `5.5.0` | 2024-12-20 |
| Windows 11 | `win11-arm` | `5.6.0` | `5.6.0` | 2025-02-23 |
| Linux (HoloOS) | `linux-x64` | `5.5.0` | `5.5.0` | 2025-01-02 |

@ -158,15 +158,15 @@ This browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
| Chrome 118 | 2024-06-29 |
| Chrome 118 | 2025-03-30 |
Browsers that do not support WebSQL will throw errors:
| Browser | Date | Error Message |
|:------------|:-----------|:------------------------------|
| Chrome 126 | 2024-06-29 | `openDatabase is not defined` |
| Safari 17.1 | 2024-06-29 | `Web SQL is deprecated` |
| Firefox 127 | 2024-06-29 | `openDatabase is not defined` |
| Chrome 133 | 2025-03-30 | `openDatabase is not defined` |
| Safari 18.3 | 2025-03-30 | `Web SQL is deprecated` |
| Firefox 136 | 2025-03-30 | `openDatabase is not defined` |
:::

@ -28,8 +28,8 @@ This demo was tested in the following environments:
| macOS | Language | Date |
|:-------|:------------------|:-----------|
| `14.5` | AppleScript (OSA) | 2024-06-30 |
| `14.5` | JavaScript (JXA) | 2024-06-30 |
| `14.5` | AppleScript (OSA) | 2025-03-30 |
| `14.5` | JavaScript (JXA) | 2025-03-30 |
:::

@ -548,7 +548,7 @@ This demo was tested in the following deployments:
| Architecture | Version | Python | Date |
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `2.7.0` | `3.13.1` | 2024-12-31 |
| `darwin-arm` | `2.7.0` | `3.12.3` | 2024-06-30 |
| `darwin-arm` | `2.7.0` | `3.12.3` | 2025-03-30 |
| `linux-x64` | `2.7.0` | `3.11.7` | 2024-12-31 |
| `linux-arm` | `2.7.0` | `3.11.2` | 2025-02-15 |
@ -1020,7 +1020,7 @@ This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `2.2.0` | 2024-12-31 |
| `darwin-arm` | `2.2.0` | 2024-06-30 |
| `darwin-arm` | `2.2.0` | 2025-03-30 |
| `linux-x64` | `2.2.0` | 2024-12-31 |
| `linux-arm` | `2.2.0` | 2025-02-15 |

@ -1118,7 +1118,7 @@ This demo was last tested in the following deployments:
| Architecture | V8 Version | Javet | Java | Date |
|:-------------|:--------------|:--------|:----------|:-----------|
| `darwin-x64` | `13.2.152.16` | `4.1.1` | `22` | 2025-01-19 |
| `darwin-arm` | `12.6.228.13` | `3.1.3` | `11.0.23` | 2024-06-19 |
| `darwin-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-03-30 |
| `win11-x64` | `12.6.228.13` | `3.1.3` | `21.0.5` | 2024-12-20 |
| `linux-x64` | `12.6.228.13` | `3.1.3` | `17.0.7` | 2024-06-20 |
| `linux-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-02-16 |
@ -1149,7 +1149,8 @@ curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-v8-macos-x86_64/
<TabItem value="darwin-arm" label="ARM64 Mac">
```bash
curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-macos/3.1.3/javet-macos-3.1.3.jar
curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet/4.1.1/javet-4.1.1.jar
curl -LO https://repo1.maven.org/maven2/com/caoccao/javet/javet-v8-macos-arm64/4.1.1/javet-v8-macos-arm64-4.1.1.jar
```
</TabItem>
@ -1216,8 +1217,8 @@ java -cp ".:javet-4.1.1.jar:javet-v8-macos-x86_64-4.1.1.jar" SheetJSJavet pres.x
<TabItem value="darwin-arm" label="ARM64 Mac">
```bash
javac -cp ".:javet-macos-3.1.3.jar" SheetJSJavet.java
java -cp ".:javet-macos-3.1.3.jar" SheetJSJavet pres.xlsx
javac -cp ".:javet-4.1.1.jar:javet-v8-macos-arm64-4.1.1.jar" SheetJSJavet.java
java -cp ".:javet-4.1.1.jar:javet-v8-macos-arm64-4.1.1.jar" SheetJSJavet pres.xlsx
```
</TabItem>
@ -1279,7 +1280,7 @@ This demo was last tested in the following deployments:
| Architecture | V8 Version | Date |
|:-------------|:--------------|:-----------|
| `darwin-x64` | `12.3.219.12` | 2024-07-16 |
| `darwin-arm` | `12.3.219.12` | 2024-07-16 |
| `darwin-arm` | `12.3.219.12` | 2025-03-30 |
| `win11-x64` | `12.3.219.12` | 2024-12-20 |
| `win11-arm` | `12.3.219.12` | 2025-02-23 |
| `linux-x64` | `12.3.219.12` | 2025-01-10 |

@ -33,7 +33,7 @@ Swift on MacOS supports JavaScriptCore without additional dependencies.
| Architecture | Swift | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `6.0.2` | 2024-12-17 |
| `darwin-arm` | `5.10` | 2024-06-30 |
| `darwin-arm` | `6.0.3` | 2025-03-30 |
[**C / C++ Compiled from Source**](#c)
@ -753,13 +753,51 @@ to `SheetJSwift.xlsx`, which can be opened in a spreadsheet editor.
It is straightforward to load the platform-native (macOS) or compiled libraries
in programs built in other programming languages.
The JavaScriptCore C interface does not use "blingos" (function-like macros), so
it is possible to reference each method in an external binding.
### Rust
Writing bindings is fairly mechanical. For example, the following C code
creates a string within the engine from a UTF8 string:
Writing bindings is fairly mechanical. There are 4 parts to the process:
```c
JSStringRef script = JSStringCreateWithUTF8CString("SheetJS");
0) Link to the external library.
1) Generate Rust representations of the original C data types.
2) Translate the function declaration.
3) Write a wrapper to convert between Rust concepts and C concepts.
For example, the following C code creates a string within the engine from a
UTF8 string:
```c title="Sample use of JSStringCreateWithUTF8CString"
const char *code = "'Sheet' + 'JS'";
JSStringRef script = JSStringCreateWithUTF8CString(code);
```
An ergonomic wrapper function would take a Rust string literal and handle unsafe
data operations:
```rust title="Theoretical equivalent in Rust"
let code: &str = "'Sheet' + 'JS'";
let script: JSStringRef = JSC::JSStringCreateWithUTF8CString(code);
```
**Rust Linkage**
Custom directives are typically added to `build.rs`. The `cargo::rustc-link-lib`
directive instructs the Rust compiler to link against an external library.
The following snippet will instruct the toolchain to link against the system
`JavaScriptCore.framework` framework on macOS:
```rust title="build.rs (link to JavaScriptCore.framework on macOS)"
#[cfg(target_os = "macos")]
fn main() {
// highlight-next-line
println!("cargo::rustc-link-lib=framework=JavaScriptCore");
}
```
**Rust Types**
@ -767,7 +805,7 @@ JSStringRef script = JSStringCreateWithUTF8CString("SheetJS");
`JSStringRef` is a pointer to an opaque data type. The spiritual equivalent
according to the Rustonomicon is a pointer to an opaque struct[^9]:
```rust
```rust title="JSStringRef opaque type in Rust"
#[repr(C)]
pub struct JSString {
_data: [u8; 0],
@ -779,7 +817,7 @@ type JSStringRef = *mut JSContext;
**Function Declaration**
The `JSStringCreateWithUTF8CString` function in declared in C as follows:
The `JSStringCreateWithUTF8CString` function is declared in C as follows:
```c
JSStringRef JSStringCreateWithUTF8CString(const char * string);
@ -787,8 +825,9 @@ JSStringRef JSStringCreateWithUTF8CString(const char * string);
The equivalent Rust declaration must be defined in an `extern "C"` block:
```rust
```rust title="JSStringCreateWithUTF8CString Rust declaration"
unsafe extern "C" {
// JSStringRef JSStringCreateWithUTF8CString(const char * string);
pub unsafe fn JSStringCreateWithUTF8CString(string: *const u8) -> JSStringRef;
}
```
@ -825,7 +864,7 @@ let ref: JSStringRef = JSStringCreateWithUTF8CString(cstr.as_ptr() as *const u8)
The demo makes a safe wrapper to perform the unsafe waltz in one line:
```rust
```rust title="Ergonomic wrapper for JSStringCreateWithUTF8CString"
pub struct JSC;
impl JSC {
pub fn JSStringCreateWithUTF8CString(str: &str) -> JSStringRef { unsafe {

@ -177,7 +177,7 @@ This demo was tested in the following deployments:
| Architecture | Jurassic | Date |
|:-------------|:---------|:-----------|
| `darwin-x64` | `3.2.8` | 2024-12-17 |
| `darwin-arm` | `3.2.7` | 2024-06-15 |
| `darwin-arm` | `3.2.9` | 2025-03-30 |
| `win11-x64` | `3.2.8` | 2024-12-19 |
| `win11-arm` | `3.2.9` | 2025-02-23 |
| `linux-x64` | `3.2.8` | 2025-01-10 |

@ -144,11 +144,11 @@ worker.addEventListener('message', function(e) {
:::danger pass
Each moving part in this solution has been deprecated years ago:
Each moving part in this solution has been deprecated many years ago:
- Adobe stopped supporting Flash Player at the end of 2020
- Microsoft stopped supporting IE8 in 2019 and stopped supporting IE9 in 2020
- `Downloadify` support ended in 2010 and `SWFObject` support ended in 2016
- Adobe discontinued Flash Player
- Microsoft discontinued Internet Explorer
- `Downloadify` and `SWFObject` are no longer supported
New projects should strongly consider requiring modern browsers. This info is
provided on an "as is" basis and there is no realistic way to provide support

@ -340,9 +340,9 @@ _Assign a dynamic array formula_
XLSX.utils.sheet_set_array_formula(worksheet, range, formula, true);
```
Released in 2020, Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB
file formats. They are represented like normal array formulae but have special
cell metadata indicating that the formula should be allowed to adjust the range.
Dynamic Array Formulae are supported in the XLSX/XLSM and XLSB file formats.
They are internally stored as normal array formulae but have special cell
metadata indicating that the formula should be allowed to adjust the range.
An array formula can be marked as dynamic by setting the cell `D` property to
true. The `F` range is expected but can be the set to the current cell:

@ -15,12 +15,12 @@
"make": "electron-forge make"
},
"devDependencies": {
"@electron-forge/cli": "7.6.0",
"@electron-forge/maker-deb": "7.6.0",
"@electron-forge/maker-rpm": "7.6.0",
"@electron-forge/maker-squirrel": "7.6.0",
"@electron-forge/maker-zip": "7.6.0",
"electron": "33.2.1"
"@electron-forge/cli": "7.8.0",
"@electron-forge/maker-deb": "7.8.0",
"@electron-forge/maker-rpm": "7.8.0",
"@electron-forge/maker-squirrel": "7.8.0",
"@electron-forge/maker-zip": "7.8.0",
"electron": "35.1.2"
},
"config": {
"forge": {

@ -10,6 +10,7 @@ type AOA = any[][];
selector: 'app-home',
//templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
standalone: false,
template: `
<ion-header>
<ion-toolbar>

@ -10,7 +10,7 @@ export default defineConfig({
vue(),
{ // this plugin handles ?sheetjs tags
name: "vite-sheet",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?sheetjs$/)) return;
var wb = read(readFileSync(id.replace(/\?sheetjs$/, "")));
var data = utils.sheet_to_json(wb.Sheets[wb.SheetNames[0]]);
@ -19,7 +19,7 @@ export default defineConfig({
},
{ // this plugin handles ?html tags
name: "vite-sheet-html",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?html/)) return;
var wb = read(readFileSync(id.replace(/\?html/, "")));
var html = utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
@ -28,7 +28,7 @@ export default defineConfig({
},
{ // this plugin handles ?b64 tags
name: "vite-b64-plugin",
transform(code, id) {
transform(_code, id) {
if(!id.match(/\?b64$/)) return;
var path = id.replace(/\?b64/, "");
var data = readFileSync(path, "base64");

@ -1,72 +1,109 @@
#!/bin/bash
# https://docs.sheetjs.com/docs/demos/frontend/bundler/vitejs
# NOTE: this only checks whether data or SheetJS code is added to the bundle
cd /tmp
rm -rf sheetjs-vite-tests
mkdir sheetjs-vite-tests
cd sheetjs-vite-tests
for n in {3..5}; do
npm create vite@$n sheetjs-vite$n -- --template vue-ts
for n in {3..6}; do
npm create -y vite@$n sheetjs-vite$n -- --template vue-ts
cd sheetjs-vite$n
npm i
npm i --save puppeteer express@4
npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
npm ls | grep vite
## See https://github.com/vuejs/language-tools/issues/4484#issuecomment-2182469459
if [[ "$n" == "4" ]]; then npm i "vue-tsc@2"; fi
curl -O https://docs.sheetjs.com/vitejs/vite.config.ts
mkdir -p data
curl -L -o data/pres.xlsx https://sheetjs.com/pres.xlsx
curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx
cat >src/components/HelloWorld.vue <<EOF
<script setup lang="ts">
// @ts-ignore
import data from '../../data/pres.xlsx?sheetjs';
import { version, utils, writeFileXLSX } from 'xlsx';
interface President {
terms: { "type": "prez" | "viceprez"; }[];
name: { first: string; last: string; }
bio: { birthday: string; }
}
async function xport() {
/* fetch JSON data and parse */
const url = "https://docs.sheetjs.com/executive.json";
const raw_data: President[] = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* sort by first presidential term */
prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start);
prez.sort((l,r) => l.start.localeCompare(r.start));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = utils.json_to_sheet(rows);
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsx */
console.log(utils.sheet_to_csv(worksheet));
writeFileXLSX(workbook, "Presidents.xlsx");
}
</script>
<template>
<table>
<tr><th>Name</th><th>Index</th></tr>
<tr v-for="(row,R) in data" v-bind:key="R">
<td>{{row.Name}}</td>
<td>{{row.Index}}</td>
</tr>
</table>
<button type="button" @click="xport">Export with SheetJS version {{ version }}</button>
</template>
EOF
npm run build
echo "### Results: " $(grep Clinton -R dist | wc -l) $(grep BESSELJ -R dist | wc -l)
npx vite build
cat >src/components/HelloWorld.vue <<EOF
<script setup lang="ts">
// @ts-ignore
import b64 from '../../data/pres.xlsx?b64';
import { read, utils } from "xlsx";
/* parse workbook and convert first sheet to row array */
const wb = read(b64);
const ws = wb.Sheets[wb.SheetNames[0]];
interface IPresident { Name: string; Index: number; };
const data = utils.sheet_to_json<IPresident>(ws);
</script>
<template>
<table>
<tr><th>Name</th><th>Index</th></tr>
<tr v-for="(row,R) in data" v-bind:key="R">
<td>{{row.Name}}</td>
<td>{{row.Index}}</td>
</tr>
</table>
</template>
cat >test.cjs <<EOF
const puppeteer = require('puppeteer');
const express = require('express');
const app = express();
app.use(express.static('./dist/'));
app.listen(7262, async() => {
await new Promise((res,rej) => setTimeout(res, 1000));
const browser = await puppeteer.launch();
const page = await browser.newPage();
page.on("console", msg => console.log("PAGE LOG:", msg.text()));
await page.setViewport({width: 1920, height: 1080});
const client = await page.target().createCDPSession();
await client.send('Browser.setDownloadBehavior', {
behavior: 'allow',
downloadPath: require("path").resolve('./')
});
page.on('request', req => console.log(req.url()));
await page.goto('http://localhost:7262/');
await page.click("button");
await new Promise((res,rej) => setTimeout(res, 1000));
await browser.close();
process.exit();
});
EOF
npm run build
echo "### Results: " $(grep Clinton -R dist | wc -l) $(grep BESSELJ -R dist | wc -l)
node test.cjs
npx -y xlsx-cli Presidents.xlsx | head -n 3
rm -f Presidents.xlsx
cd -
done

@ -6,7 +6,7 @@ rm -rf sheetjs-vite-static
mkdir sheetjs-vite-static
cd sheetjs-vite-static
for n in {2..5}; do
for n in {2..6}; do
npm create -y vite@$n sheetjs-vite-$n -- --template vue-ts
cd sheetjs-vite-$n
npm i
@ -24,9 +24,13 @@ if [[ "$n" == "2" ]]; then
# Please update to v0.35.0 or higher for TypeScript version: 4.9.5
#
# Forcefully upgrading `vue-tsc` appears to be innocuous.
npm i --save vue-tsc@latest
npm i --save "vue-tsc@1.x"
elif [[ "$n" == "4" ]]; then
# Search string not found: "/supportedTSExtensions = .*(?=;)/"
npm i --save "vue-tsc@2"
fi
curl -O https://docs.sheetjs.com/vitejs/vite.config.ts
mkdir -p data
curl -L -o data/pres.xlsx https://docs.sheetjs.com/pres.xlsx