forked from sheetjs/docs.sheetjs.com
azure
This commit is contained in:
parent
62641b5da6
commit
990f42934b
@ -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/' },
|
||||
|
BIN
docz/static/azure/bloblobber.png
Normal file
BIN
docz/static/azure/bloblobber.png
Normal file
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:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user