14 KiB
title | pagination_prev | pagination_next |
---|---|---|
Cloudflare | demos/local/index | demos/extensions/index |
import current from '/version.js'; import CodeBlock from '@theme/CodeBlock';
Cloudflare is a cloud services platform which includes "Serverless Functions" and cloud storage.
SheetJS is a JavaScript library for reading and writing data from spreadsheets.
This demo explores two key Cloudflare offerings:
-
"Cloudflare Workers" explores the serverless computing offering. The demo creates a JavaScript function that can process user-submitted files and generate spreadsheets.
-
"Cloudflare R2" explores the cloud storage ("R2") offering. The demo uses the NodeJS connection library to read spreadsheets from R2 and write spreadsheets to an R2 bucket.
:::note Tested Deployments
This demo was last tested on 2024 April 02.
:::
Cloudflare Workers
Cloudflare offers NodeJS runtimes for running JavaScript serverless functions.1
The SheetJS NodeJS module can be required in Cloudflare Workers. Cloudflare provides a cli called C3 2 in order to setup your worker project and another cli called Wrangler 3 which can streamline development and deployment,
:::note pass
In this demo, Wrangler is used as that is Cloudflare's recommended way of developing and deploying to Workers
:::
Overview
Cloudflare Workers exposes a handler in src/index.(js|ts) when you create a worker project using C3 as per above, this handler exposes a Request object which can be used to expose the formdata or json of the request to the worker
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const data = await request.formData()
// const data = await request.json() if you are receiving a json request
//...
},
};
Reading Data
The SheetJS read
method4 can read ArrayBuffer objects and generate SheetJS
workbook objects5 which can be processed with other API functions.
For example, a handler can use sheet_to_csv
6 to generate CSV text:
import XLSX from "xlsx";
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
if (request.method === 'POST') {
const data = await request.formData()
// const data = await request.json() if you are doing a json request
const file = data.get('file') as File;
const buffer = await file.arrayBuffer();
const wb = XLSX.read(buffer);
const ws = wb.Sheets[wb.SheetNames[0]];
var b64 = XLSX.write(wb, { type: "base64", bookType: "xlsx" });
return new Response(XLSX.utils.sheet_to_csv(ws))
}
return new Response('Hello World!');
},
};
Writing Data
import XLSX from "xlsx";
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
var data = XLSX.write(wb, { type: "buffer", bookType: "xlsx" });
return new Response(data,{
status: 200,
headers: {
"Content-Disposition": 'attachment; filename="SheetJSCFWorker.xlsx"' //Content disposition will make the browser download the file
}
})
},
};
Cloudflare Workers Demo
:::note pass
At the time of writing, the Cloudflare Workers Free Tier included an allowance of 100,000 free requests per day and 10 milliseconds of CPU time per invocation.
:::
- If you do not have an account, create a new account7.
Setting up the Project and Testing
Cloudflare R2
The main NodeJS module for S3 and all Cloudflare services is Cloudflare-sdk
8.
The SheetJS NodeJS module can be required in NodeJS scripts.
Connecting to R2
The Cloudflare-sdk
module exports a function S3
that performs the connection. The
function expects an options object that includes an API version and credentials.
Access keys for an IAM user9 must be used:
/* credentials */
var accessKeyId = "...", secretAccessKey = "..."";
/* file location */
var Bucket = "...", Key = "pres.numbers";
/* connect to s3 account */
var Cloudflare = require('Cloudflare-sdk');
var s3 = new Cloudflare.S3({
apiVersion: '2006-03-01',
credentials: { accessKeyId, secretAccessKey }
});
Downloading Data
Fetching Files from S3
The s3#getObject
method returns an object with a createReadStream
method.
createReadStream
returns a NodeJS stream:
/* open stream to the file */
var stream = s3.getObject({ Bucket: Bucket, Key: Key }).createReadStream();
Concatenating NodeJS Streams
Buffers can be concatenated from the stream into one unified Buffer object:
/* array of buffers */
var bufs = [];
/* add each data chunk to the array */
stream.on('data', function(data) { bufs.push(data); });
/* the callback will be called after all of the data is collected */
stream.on('end', function() {
/* concatenate */
var buf = Buffer.concat(bufs);
/* AT THIS POINT, `buf` is a NodeJS Buffer */
});
Parsing NodeJS Buffers
The SheetJS read
method10 can read the final object and generate SheetJS
workbook objects11 which can be processed with other API functions.
For example, a callback can use sheet_to_csv
12 to generate CSV text:
stream.on('end', function() {
/* concatenate */
var buf = Buffer.concat(bufs);
/* parse */
var wb = XLSX.read(Buffer.concat(bufs));
/* generate CSV from first worksheet */
var first_ws = wb.Sheets[wb.SheetNames[0]];
var csv = XLSX.utils.sheet_to_csv(first_ws);
console.log(csv);
});
Uploading Data
The SheetJS write
method13 with the option type: "buffer"
will generate
NodeJS Buffers. S3#upload
directly accepts these Buffer objects.
This example creates a sample workbook object, generates XLSX file data in a NodeJS Buffer, and uploads the data to S3:
/* generate sample workbook */
var wb = XLSX.read("S,h,e,e,t,J,S\n5,4,3,3,7,9,5", {type: "binary"});
/* write to XLSX file in a NodeJS Buffer */
var Body = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
/* upload buffer */
s3.upload({ Bucket, Key, Body }, function(err, data) {
if(err) throw err;
console.log("Uploaded to " + data.Location);
});
S3 Demo
:::note pass
At the time of writing, the Cloudflare Free Tier included 5GB of Cloudflare R2 with 20,000 Get requests and 2000 Put requests per month.
:::
This sample fetches a buffer from S3 and parses the workbook.
- If you do not have an account, create a new Cloudflare free tier account14.
Create S3 Bucket
-
Sign into the Cloudflare Management Console with a root user account.
-
Type "S3" in the top search box and click S3 (under Services).
-
Open "Buckets" in the left sidebar.
If the left sidebar is not open, click the ≡
icon in the left edge of the page.
-
Click the "Create bucket" button in the main panel.
-
Select the following options:
-
Type a memorable "Bucket Name" ("sheetjsbouquet" when last tested)
-
In the "Object Ownership" section, select "ACLs disabled"
-
Check "Block all public access"
-
Look for the "Bucket Versioning" section and select "Disable"
- Click "Create bucket" to create the bucket.
Create IAM User
-
Type "IAM" in the top search box and click IAM (under Services).
-
Open "Users" in the left sidebar.
If the left sidebar is not open, click the ≡
icon in the left edge of the page.
-
Click the "Create user" button in the main panel.
-
In step 1, type a memorable "Bucket Name" ("sheetjs-user" when last tested). Click "Next".
-
In step 2, click "Next"
-
In step 3, click "Create user" to create the user.
Add Permissions
-
Click the new user name in the Users table.
-
Select the "Permissions" tab
-
Click the "Add permissions" dropdown and select "Add permissions".
-
Select "Attach policies directly".
-
In the "Permissions policies" section, search for "AmazonS3FullAccess". There should be one entry.
-
Check the checkbox next to "AmazonS3FullAccess" and click the "Next" button.
-
In the "Review" screen, click "Add permissions"
Generate Keys
-
Click "Security credentials", then click "Create access key".
-
Select the "Local code" option. Check "I understand the above recommendation and want to proceed to create an access key." and click "Next"
-
Click "Create Access Key" and click "Download .csv file" in the next screen.
In the generated CSV:
- Cell A2 is the "Access key ID" (
accessKeyId
in the Cloudflare API) - Cell B2 is the "Secret access key" (
secretAccessKey
in the Cloudflare API)
Set up Project
- Create a new NodeJS project:
mkdir SheetJSS3
cd SheetJSS3
npm init -y
- Install dependencies:
{\ mkdir -p node_modules npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz Cloudflare-sdk@2.1467.0
}
Write Test
:::note pass
This sample creates a simple workbook, generates a NodeJS buffer, and uploads the buffer to S3.
| A | B | C | D | E | F | G |
---+---|---|---|---|---|---|---|
1 | S | h | e | e | t | J | S |
2 | 5 | 4 | 3 | 3 | 7 | 9 | 5 |
:::
- Save the following script to
SheetJSWriteToS3.js
:
var XLSX = require("xlsx");
var Cloudflare = require('Cloudflare-sdk');
/* replace these constants */
// highlight-start
var accessKeyId = "<REPLACE WITH ACCESS KEY ID>";
var secretAccessKey = "<REPLACE WITH SECRET ACCESS KEY>";
var Bucket = "<REPLACE WITH BUCKET NAME>";
// highlight-end
var Key = "test.xlsx";
/* Create a simple workbook and write XLSX to 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, "Sheet1");
var Body = XLSX.write(wb, {type: "buffer", bookType: "xlsx"});
/* upload buffer */
var s3 = new Cloudflare.S3({
apiVersion: '2006-03-01',
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
}
});
s3.upload({ Bucket: Bucket, Key: Key, Body: Body }, function(err, data) {
if(err) throw err;
console.log("Uploaded to " + data.Location);
});
- Edit
SheetJSWriteToS3.js
and replace the highlighted lines:
accessKeyId
: access key for the Cloudflare accountsecretAccessKey
: secret access key for the Cloudflare accountBucket
: name of the bucket
The keys are found in the CSV from step 22. The Bucket is the name from step 5.
- Run the script:
node SheetJSWriteToS3.js
This file will be stored with the object name test.xlsx
. It can be manually
downloaded from the S3 web interface.
Read Test
This sample will download and process the test file from "Write Test".
- Save the following script to
SheetJSReadFromS3.js
:
var XLSX = require("xlsx");
var Cloudflare = require('Cloudflare-sdk');
/* replace these constants */
// highlight-start
var accessKeyId = "<REPLACE WITH ACCESS KEY ID>";
var secretAccessKey = "<REPLACE WITH SECRET ACCESS KEY>";
var Bucket = "<REPLACE WITH BUCKET NAME>";
// highlight-end
var Key = "test.xlsx";
/* Get stream */
var s3 = new Cloudflare.S3({
apiVersion: '2006-03-01',
credentials: {
accessKeyId: accessKeyId,
secretAccessKey: secretAccessKey
}
});
var f = s3.getObject({ Bucket: Bucket, Key: Key }).createReadStream();
/* collect data */
var bufs = [];
f.on('data', function(data) { bufs.push(data); });
f.on('end', function() {
/* concatenate and parse */
var wb = XLSX.read(Buffer.concat(bufs));
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
});
- Edit
SheetJSReadFromS3.js
and replace the highlighted lines:
accessKeyId
: access key for the Cloudflare accountsecretAccessKey
: secret access key for the Cloudflare accountBucket
: name of the bucket
The keys are found in the CSV from Step 22. The Bucket is the name from Step 5.
- Run the script:
node SheetJSReadFromS3.js
The program will display the data in CSV format.
S,h,e,e,t,J,S
5,4,3,3,7,9,5
-
See "Node.js compatibility" in the Cloudflare documentation ↩︎
-
See "Workbook Object" in "SheetJS Data Model" for more details. ↩︎
-
Registering for a free account on the Cloudflare Free Tier. ↩︎
-
The
Cloudflare-sdk
module is distributed on the public NPM registry ↩︎ -
See "Managing access keys for IAM users" in the Cloudflare documentation ↩︎
-
See "Workbook Object" in "SheetJS Data Model" for more details. ↩︎
-
Registering for a free account on the Cloudflare Free Tier requires a valid phone number and a valid credit card. ↩︎