This commit is contained in:
SheetJS 2023-10-06 16:47:17 -04:00
parent 62641b5da6
commit 990f42934b
8 changed files with 632 additions and 139 deletions

@ -25,7 +25,7 @@ This demo was verified by NetSuite consultants in the following deployments:
| `@NScriptType` | `@NApiVersion` | Date |
|:----------------|:---------------|:-----------|
| ScheduledScript | 2.1 | 2023-08-18 |
| Restlet | 2.1 | 2023-04-20 |
| Restlet | 2.1 | 2023-10-05 |
| Suitelet | 2.1 | 2023-07-21 |
| MapReduceScript | 2.1 | 2023-07-31 |

@ -311,7 +311,7 @@ Function properties.
17) Select the "Configuration" tab and select "Permissions" in the left sidebar.
18) Scroll down to "Resource-based policy statements" and ensure that
18) Scroll down to "Resource-based policy statements" and ensure that
`FunctionURLAllowPublicAccess` is listed.
If no policy statements are defined, select "Add Permission" with the options:
@ -373,7 +373,7 @@ var s3 = new AWS.S3({
```
### Reading Data
### Downloading Data
#### Fetching Files from S3
@ -425,7 +425,7 @@ stream.on('end', function() {
});
```
### Writing Data
### Uploading Data
The SheetJS `write` method[^13] with the option `type: "buffer"` will generate
NodeJS Buffers. `S3#upload` directly accepts these Buffer objects.

@ -5,10 +5,26 @@ pagination_next: demos/extensions/index
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
Azure is a Cloud Services platform which includes traditional virtual machine
support, "Serverless Functions", cloud storage and much more.
[Azure Cloud Services](https://azure.microsoft.com/) is a Cloud Services
platform which includes traditional virtual machine support, "Serverless
Functions" and cloud storage.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo explores two key AWS offerings:
- ["Azure Functions"](#azure-functions) ("Lambda") explores the serverless
computing offering. The demo creates a JavaScript function that can process
user-submitted files and generate spreadsheets.
- ["Blob Storage"](#blob-storage) explores the cloud storage offering. The demo
uses the NodeJS connection library to read spreadsheets from storage and write
spreadsheets back to cloud storage.
:::caution pass
@ -17,22 +33,77 @@ will be available in the future.
:::
This demo focuses on two key offerings: cloud storage ("Azure Blob Storage")
and the "Serverless Function" platform ("Azure Functions").
:::note
This demo was last tested on 2023 April 29.
This demo was last tested on 2023 October 06.
:::
## Telemetry
:::warning Telemetry
**Each command-line tool related to Azure embeds telemetry.**
Azure tools embed telemetry without proper disclaimer.
:::
It is strongly recommended to disable telemetry before working with Azure.
#### Azure Functions Core Tools
Azure Functions Core Tools (`func`) telemetry is controlled through the
`FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` environment variable.
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
Add the following line to `.profile`, `.bashrc` and `.zshrc`:
```bash
export FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT=1
```
Close and restart the Terminal to load the changes.
</TabItem>
<TabItem value="win" label="Windows">
Type `env` in the search bar and select "Edit the system environment variables".
In the new window, click the "Environment Variables..." button.
In the new window, look for the "System variables" section and click "New..."
Set the "Variable name" to `FUNCTIONS_CORE_TOOLS_TELEMETRY_OPTOUT` and the value
to `1`.
Click "OK" in each window (3 windows) and restart your computer.
</TabItem>
</Tabs>
#### Azure CLI
Azure CLI (`az`) telemetry can be disabled using a subcommand (after installing
the CLI tool)[^1]:
```bash
az configure -d collect_telemetry=false
```
## Azure Functions
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
required in Azure Functions that use the NodeJS runtime.
This discussion focuses on the "HTTP Trigger" function type.
:::info pass
:::note pass
To enable binary data processing, a setting must be changed in `function.json`:
In earlier tests, to enable binary data processing, `function.json` required a
`dataType` option:
```json title="function.json"
{
@ -45,150 +116,295 @@ To enable binary data processing, a setting must be changed in `function.json`:
"name": "req",
```
In the most recent test, the template did not create a `function.json` and the
option was not required.
:::
### Reading Data
`formidable` expects a stream and Azure does not present one. It can be made:
Using `@azure/functions`, the handler callback receives a `Request` object. With
standard JS operations, the file can be pulled into an `ArrayBuffer` object.
The SheetJS `read` method[^2] can read the `ArrayBuffer` objects and generate
SheetJS workbook objects[^3] which can be processed with other API functions.
For example, a handler can use `sheet_to_csv`[^4] to generate CSV text:
```js
const { Blob } = require('buffer');
const { app } = require('@azure/functions');
const XLSX = require('xlsx');
const formidable = require('formidable');
const Readable = require('stream').Readable;
/* formidable expects the request object to be a stream */
const streamify = (req) => {
if(typeof req.on !== 'undefined') return req;
const s = new Readable();
s._read = ()=>{};
s.push(Buffer.from(req.body));
s.push(null);
Object.assign(s, req);
return s;
};
app.http('SheetJSAzure', {
methods: ['POST'],
handler: async (req, context) => {
/* grab the file at form key `upload` */
const formData = await req.formData();
const f = formData.get("upload");
module.exports = (context, req) => {
const form = new formidable.IncomingForm();
form.parse(streamify(req), (err, fields, files) => {
/* grab the first file */
var f = files["upload"];
if(!f) {
context.res = { status: 400, body: "Must submit a file for processing!" };
} else {
/* file is stored in a temp directory, so we can point to that and read it */
const wb = XLSX.read(f.filepath, {type:"file"});
if(!(f instanceof Blob)) return { status: 400, body: "Must submit a file" };
/* generate CSV from first sheet */
const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
context.res = { status: 200, body: csv };
}
context.done();
});
}
/* parse file */
const ab = await f.arrayBuffer();
const wb = XLSX.read(ab);
/* generate CSV from first sheet */
const ws = wb.Sheets[wb.SheetNames[0]];
const csv = XLSX.utils.sheet_to_csv(ws);
return { status: 200, body: csv };
}
});
```
### Writing Data
The `body` property can be a Buffer, like those generated by `XLSX.write`:
The SheetJS `write` method[^5] with the option `type: "buffer"` will generate
NodeJS buffers which can be sent in the callback handler response.
The following example generates a sample worksheet using the `aoa_to_sheet`[^6]
method, generates a sample workbook using worksheet helper methods[^7], writes
the workbook to XLSX format in a Buffer, and sends the Buffer in the response:
```js
const { app } = require('@azure/functions');
const XLSX = require('xlsx');
module.exports = (context, req) => {
// generate XLSX file in a Buffer
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
// highlight-next-line
var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
// Set the body and Content-Disposition header
// highlight-start
context.res = {
status: 200,
headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
body: buf
};
// highlight-end
context.done();
};
app.http('SheetJSAzure', {
methods: ['GET'],
handler: async (req, context) => {
/* generate sample worksheet */
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5, 4, 3, 3, 7, 9, 5]]);
/* generate workbook */
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
/* write to XLSX, returning a NodeJS Buffer */
var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
/* send Buffer to client */
return {
status: 200,
/* Content-Disposition header */
headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
/* data */
body: buf
};
}
});
```
### Demo
### Functions Demo
<details open><summary><b>Complete Example</b> (click to show)</summary>
:::note pass
0) Review the quick start for JavaScript on Azure Functions. This involves
installing the Azure Functions Core Tools and other dependencies.
At the time of writing, the Azure Free Tier included an allowance of 1 million
free requests per month.
1) Create a new project and install dependencies:
:::
0) If you do not have an account, create a new Azure free tier account[^8].
#### Local Setup
1) [Disable Azure Functions Core Tools Telemetry](#azure-functions-core-tools).
2) Install the CLI tool using npm:
```bash
npm i -g azure-functions-core-tools@4 --unsafe-perm true
```
:::note pass
On macOS and Linux, `sudo` may be required:
```bash
sudo npm i -g azure-functions-core-tools@4 --unsafe-perm true
```
:::
3) Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
4) Disable Azure CLI telemetry:
```bash
az configure -d collect_telemetry=false
```
#### Start Project
5) Create a new JavaScript HTTP Trigger project:
```bash
mkdir SheetJSAzure
cd SheetJSAzure
func new --template httpTrigger --language JavaScript --name SheetJSAzure
```
:::warning pass
When the demo was last tested, the stock TypeScript template did not work.
**This is a bug in the Azure Functions Core Tools**
Until the bugs are resolved, JavaScript should be preferred over TypeScript.
:::
6) Start the local server:
```bash
npm start
```
7) While the server is running, open a new terminal window and make a request:
```bash
curl -L http://localhost:7071/api/SheetJSAzure
```
The terminal should display `Hello, world!`
#### Add SheetJS
8) Install the SheetJS NodeJS module:
<CodeBlock language="bash">{`\
func init sheetjs-azure --worker-runtime node --language javascript
cd sheetjs-azure
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz formidable`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
2) Create a new "HTTP Trigger" function:
9) Download [the sample script](pathname:///azure/index.js):
```bash
func new --template "Http Trigger" --name SheetJSAzure
curl -L -o src/functions/SheetJSAzure.js https://docs.sheetjs.com/azure/index.js
```
3) Edit `SheetJSAzure/function.json` to add the `dataType: "binary"` property:
#### Local Test
```js title="SheetJSAzure/function.json"
"direction": "in",
// highlight-next-line
"dataType": "binary",
"name": "req",
```
4) Download [`SheetJSAzure/index.js`](pathname:///aws/index.js):
10) Stop and restart the dev server:
```bash
curl -L -o SheetJSAzure/index.js https://docs.sheetjs.com/azure/index.js
npm start
```
5) Test locally with `npm start`
To test uploads, download <https://sheetjs.com/pres.numbers> and run:
11) In a separate terminal window, download <https://sheetjs.com/pres.numbers>
and make a POST request to the dev server:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -X POST -F "upload=@pres.numbers" http://localhost:7071/api/SheetJSAzure
```
To test downloads, access `http://localhost:7071/api/SheetJSAzure` and download
the generated file. Confirm it is a valid file.
If the test succeeded, the terminal will print CSV rows from the test file data.
6) Deploy to Azure. Replace `NAME_OF_FUNCTION_APP` with the name:
12) Open a web browser and access `http://localhost:7071/api/SheetJSAzure` .
```bash
func azure functionapp publish NAME_OF_FUNCTION_APP
If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`.
Open in Excel or another spreadsheet editor to confirm the file is valid.
#### Create Remote Function
13) Sign into the [Azure Portal](https://portal.azure.com/#home)
14) Type "Function App" in the top search box and click "Function App"
15) Click "+ Create"
16) Select the following options:
- Type a memorable "Function Name" ("sheetjsazure" when last tested)
- "Do you want to deploy code or container image?": select "Code"
- "Runtime stack": select NodeJS
- "Hosting options and plans": "Consumption (Serverless)"
17) Click "Review + create", then click "Create" to create the function.
The page will display a status message
> ... Deployment is in progress
When the resources are configured, the status will change to
> Your deployment is complete
18) Click "Go to Resource".
19) Take note of the URL from the table
#### Deploy to Azure
20) Sign into Azure:
```
az login
```
Get the function URL and test using the same sequence as in step 5.
The login flow resumes in the browser.
</details>
21) Deploy to Azure. Replace `FUNCTION_NAME` with the name from Step 16:
## Azure Blob Storage
```bash
func azure functionapp publish FUNCTION_NAME
```
After publishing, the process will print the "Invoke url":
```
Functions in sheetjsazure:
SheetJSAzure - [httpTrigger]
// highlight-next-line
Invoke url: https://sheetjsazure.azurewebsites.net/api/sheetjsazure
```
Take note of that URL.
#### Remote Test
22) In a separate terminal window, download <https://sheetjs.com/pres.numbers>
and make a POST request to the production server. Replace `FUNCTION_URL` with
the Invoke URL from Step 21:
```bash
curl -LO https://sheetjs.com/pres.numbers
curl -X POST -F "upload=@pres.numbers" FUNCTION_URL
```
If the test succeeded, the terminal will print CSV rows from the test file data.
23) Open a web browser and access the Invoke URL from Step 21.
If the test succeeded, the browser will attempt to download `SheetJSAzure.xlsx`.
Open in Excel or another spreadsheet editor to confirm the file is valid.
## Blob Storage
The main module for Azure Blob Storage is `@azure/storage-blob`. This example
was tested using the "Connection String" authentication method. The strings
are found in the Azure Portal under "Access Keys" for the storage account.
### Reading Data
### Downloading Data
The `BlobClient#download` method returns a Stream. After collecting into a
Buffer, `XLSX.read` can parse the data:
Buffer, the SheetJS `read` method[^9] can parse the data into a workbook[^10].
The following demo uses the `sheet_to_csv`[^11] utility function to display the
contents of a file in Azure Blob Storage:
```js title="SheetJSReadFromAzure.mjs"
import { BlobServiceClient } from "@azure/storage-blob";
import { read, utils } from "xlsx";
/* replace these constants */
// highlight-start
const connStr = "<REPLACE WITH CONNECTION STRING>";
const containerName = "<REPLACE WITH CONTAINER NAME>";
const blobName = "<REPLACE WITH BLOB NAME>";
// highlight-end
/* Blob name */
const blobName = "SheetJSBloblobber.xlsx";
/* get a readable stream*/
const blobServiceClient = BlobServiceClient.fromConnectionString(connStr);
@ -207,18 +423,27 @@ const wb = read(downloaded);
console.log(utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
```
### Writing Data
### Uploading Data
`BlockBlobClient#upload` directly accepts a Buffer:
The SheetJS `write` method[^12] with the option `type: "buffer"` will generate
NodeJS buffers which can be uploaded with `BlockBlobClient#upload`.
The following example generates a sample worksheet using the `aoa_to_sheet`[^13]
method, generates a sample workbook using worksheet helper methods[^14], writes
the workbook to XLSX format in a Buffer, and sends the Buffer in the response:
```js title="SheetJSWriteToAzure.mjs"
import { BlobServiceClient } from "@azure/storage-blob";
import { write, utils } from "xlsx";
/* replace these constants */
// highlight-start
const connStr = "<REPLACE WITH CONNECTION STRING>";
const containerName = "<REPLACE WITH CONTAINER NAME>";
const blobName = "<REPLACE WITH BLOB NAME>";
// highlight-end
/* Blob name */
const blobName = "SheetJSBloblobber.xlsx";
/* Create a simple workbook and write XLSX to buffer */
const ws = utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
@ -231,3 +456,165 @@ const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.upload(buf, buf.length);
```
### Blob Demo
:::note pass
At the time of writing, new Azure accounts were granted a 12-month trial of Blob
Storage. The trial includes 5GB of "Locally-redundant storage" with 20,000 read
requests and 2000 write requests per month.
:::
0) If you do not have an account, create a new Azure free tier account[^8].
#### Storage Account Setup
1) Sign into the [Azure Portal](https://portal.azure.com/#home)
2) Type "Storage" in the top search box and click "Storage accounts"
3) Click "+ Create"
4) Select the following options:
- Type a memorable "Storage account name" ("sheetjstorage" when last tested)
- "Redundancy": select LRS (Locally-redundant storage)
- "Hosting options and plans": "Consumption (Serverless)"
5) Click "Review", then click "Create" to create the storage.
The page will display a status message
> ... Deployment is in progress
When the resources are configured, the status will change to
> Your deployment is complete
6) Click "Go to Resource".
#### Access Keys
7) Click "Access keys" in the left sidebar (under "Security + networking")
8) Look for the "Connection string" title under "key1". In the row below the
title, click "Show" to reveal the key. Click the copy icon or manually copy the
key, storing it in a safe place.
#### Container Setup
9) Click "Containers" in the left sidebar.
10) Click "+ Container"
11) Select the following options:
- Type a memorable "Name" ("sheetjs-container" when last tested)
12) Click "Create" to create the container.
#### Project Setup
13) Create a new project folder:
```bash
mkdir SheetJSBlob
cd SheetJSBlob
npm init -y
```
14) Install dependencies:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz @azure/storage-blob`}
</CodeBlock>
14) Copy the [`SheetJSReadFromAzure.mjs` code block](#downloading-data) and save
to `SheetJSReadFromAzure.mjs`.
15) Copy the [`SheetJSWriteToAzure.mjs` code block](#uploading-data) and save
to `SheetJSWriteToAzure.mjs`.
16) Edit both `SheetJSReadFromAzure.mjs` and `SheetJSWriteToAzure.mjs`:
- Replace the `connStr` value with the connection string from Step 8
- Replace the `containerName` value with the container name from Step 11
#### Test
:::note pass
The write demo creates a simple workbook, generates a NodeJS buffer, and uploads
the buffer to a file named `SheetJSBloblobber.xlsx` on Azure Blob Storage.
The read demo fetches `SheetJSBloblobber.xlsx` and displays the data.
```
| A | B | C | D | E | F | G |
---+---|---|---|---|---|---|---|
1 | S | h | e | e | t | J | S |
2 | 5 | 4 | 3 | 3 | 7 | 9 | 5 |
```
:::
17) Run the write test:
```bash
node SheetJSWriteToAzure.mjs
```
This will write the file `SheetJSBloblobber.xlsx` to the container.
18) Run the read test:
```bash
node SheetJSReadFromAzure.mjs
```
It will fetch the file created in the previous step and display CSV rows.
```
S,h,e,e,t,J,S
5,4,3,3,7,9,5
```
19) Sign into the [Azure Portal](https://portal.azure.com/#home)
20) Type "Storage" in the top search box and click "Storage accounts"
21) Click on the name of the storage
22) In the middle column, click "Containers". It will be under "Data storage".
23) Click on the name of the container in the table
24) Verify that the table shows `SheetJSBloblobber.xlsx`:
![SheetJSBloblobber.xlsx in the container](pathname:///azure/bloblobber.png)
25) Click on the name `SheetJSBloblobber.xlsx`.
26) In the right pane, click "Download".
The downloaded file is the raw file stored in Azure Blob Storage. To confirm it
is valid, open the file in Excel or another spreadsheet editor.
[^1]: The platform-specific installers are available at <https://learn.microsoft.com/en-us/cli/azure/install-azure-cli>
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^3]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
[^4]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
[^5]: See [`write` in "Writing Files"](/docs/api/write-options)
[^6]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
[^7]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.
[^8]: Registering for a free account [on the Azure Free Tier](https://azure.microsoft.com/en-us/free) requires a valid phone number and a valid credit card.
[^9]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^10]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details.
[^11]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output)
[^12]: See [`write` in "Writing Files"](/docs/api/write-options)
[^13]: See [`aoa_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-arrays-input)
[^14]: See ["Workbook Helpers" in "Utilities"](/docs/api/utilities/wb) for details on `book_new` and `book_append_sheet`.

@ -5,6 +5,8 @@ title: Overview
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
# SheetJS CE
@ -27,6 +29,9 @@ run entirely in the web browser.
<details><summary><b>How to add to your site</b> (click to show)</summary>
<Tabs groupId="deployment">
<TabItem value="vanilla" label="HTML">
1) Make sure your table has an ID:
```html
@ -45,7 +50,7 @@ run entirely in the web browser.
<button id="sheetjsexport"><b>Export as XLSX</b></button>
```
4) Add an event handler for the `click` event to create a workbook and download:
4) Add an event handler for the `click` event to export table data to XLSX:
```html
<script>
@ -58,6 +63,117 @@ document.getElementById("sheetjsexport").addEventListener('click', function() {
</script>
```
</TabItem>
<TabItem value="react" label="React">
:::note pass
This example assumes you have an existing project with an HTML TABLE element:
```jsx title="Sample Component"
function App() {
return ( <>
<h3>SheetJS Table</h3>
<table>
<tr><td colSpan="3">SheetJS Table Export</td></tr>
<tr><td>Author</td><td>ID</td><td>你好!</td></tr>
<tr><td>SheetJS</td><td>7262</td><td>வணக்கம்!</td></tr>
<tr><td colSpan="3">
<a href="//sheetjs.com">Powered by SheetJS</a>
</td></tr>
</table>
</> )
}
export default App;
```
If you are starting from scratch, create a new ViteJS + ReactJS project:
```bash
npm create vite@latest -- sheetjs-react --template react --default
cd sheetjs-react
npm install
npm run dev
```
Replace `src/App.jsx` with the sample component.
:::
1) Install the SheetJS library using a package manager:
<Tabs groupId="pm">
<TabItem value="npm" label="npm">
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
</TabItem>
</Tabs>
2) Ensure that your component script imports `useRef` from the `react` library:
```js
import { useRef } from "react";
```
3) Add the following line at the top of your component script:
```js
import { utils, writeFileXLSX } from "xlsx";
```
4) Create a ref in the body of your function component:
```jsx
function App() {
// highlight-next-line
const tbl = useRef(null);
// ...
```
5) Attach the ref to the table element:
```jsx
function App() {
// ...
return (
{/*...*/}
// highlight-next-line
<table ref={tbl}>
{/*...*/}
```
6) Add a button with a click handler that will export table data to XLSX:
```jsx
function App() {
// ...
return (
{/*...*/}
// highlight-start
<button onClick={() => {
// generate workbook from table element
const wb = utils.table_to_book(tbl.current);
// write to XLSX
writeFileXLSX(wb, "SheetJSReactExport.xlsx");
}}>Export XLSX</button>
// highlight-end
{/*...*/}
```
</TabItem>
</Tabs>
</details>
<details><summary><b>How to automate with NodeJS</b> (click to show)</summary>
@ -74,7 +190,7 @@ using the `puppeteer` and `playwright` browser automation frameworks.
function Table2XLSX(props) {
/* Callback invoked when the button is clicked */
const xport = React.useCallback(async () => {
const xport = React.useCallback(() => {
/* Create worksheet from HTML DOM TABLE */
const table = document.getElementById("Table2XLSX");
const wb = XLSX.utils.table_to_book(table);

@ -202,6 +202,7 @@ const config = {
{ from: '/docs/demos/hosting/dropbox', to: '/docs/demos/cloud/dropbox/' },
{ from: '/docs/demos/hosting/github', to: '/docs/demos/cloud/github/' },
/* data */
{ from: '/docs/getting-started/demos/database', to: '/docs/demos/data/' },
{ from: '/docs/demos/database', to: '/docs/demos/data/' },
{ from: '/docs/demos/nosql', to: '/docs/demos/data/' },
{ from: '/docs/getting-started/demos/nosql', to: '/docs/demos/data/' },

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

@ -1,49 +1,38 @@
/* sheetjs (C) SheetJS -- https://sheetjs.com */
const { Blob } = require('buffer');
const { app } = require('@azure/functions');
const XLSX = require('xlsx');
const formidable = require('formidable');
const Readable = require('stream').Readable;
/* formidable expects the request object to be a stream */
const streamify = (req) => {
if(typeof req.on !== 'undefined') return req;
const s = new Readable();
s._read = ()=>{};
s.push(Buffer.from(req.body));
s.push(null);
Object.assign(s, req);
return s;
};
app.http('SheetJSAzure', {
methods: ['GET', 'POST'],
authLevel: 'anonymous',
handler: async (req, context) => {
if (req.method == "POST") {
/* grab the file at form key `upload` */
const formData = await req.formData();
const f = formData.get("upload");
module.exports = (context, req) => {
if(req.method == "POST") {
const form = new formidable.IncomingForm();
form.parse(streamify(req), (err, fields, files) => {
/* grab the first file */
var f = files["upload"];
if(!f) {
context.res = { status: 400, body: "Must submit a file for processing!" };
if (!f || !(f instanceof Blob)) {
return { status: 400, body: "Must submit a file for processing!" };
} else {
/* file is stored in a temp directory, so we can point to that and read it */
const wb = XLSX.read(f.filepath, {type:"file"});
/* parse file */
const ab = await f.arrayBuffer();
const wb = XLSX.read(ab);
/* generate CSV from first sheet */
const csv = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
context.res = { status: 200, body: csv };
return { status: 200, body: csv };
}
context.done();
});
} else if(req.method == "GET") {
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5,4,3,3,7,9,5]]);
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
var buf = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
context.res = {
status: 200,
headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
body: buf
};
context.done();
} else {
context.res = { status: 500, body: `Unsupported method ${req.method}` };
context.done();
} else if (req.method == "GET") {
var ws = XLSX.utils.aoa_to_sheet(["SheetJS".split(""), [5, 4, 3, 3, 7, 9, 5]]);
var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Data");
var buf = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
return {
status: 200,
headers: { "Content-Disposition": `attachment; filename="SheetJSAzure.xlsx";` },
body: buf
};
} else return { status: 500, body: `Unsupported method ${req.method}` };
}
};
});

@ -1,11 +1,11 @@
/*
Licensing Note:
At the time this extract was made (2023 May 28), the linked license page
At the time this snapshot was taken, the linked license page
http://www.codeplex.com/ChinookDatabase/license
was unavailable (Microsoft shuttered CodePlex).
was unavailable (Microsoft shuttered CodePlex in 2021)
archive.org has a snapshot of the project license page: