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_csv6 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-sdk8.
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_csv12 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" (
accessKeyIdin the Cloudflare API) - Cell B2 is the "Secret access key" (
secretAccessKeyin 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.jsand 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.jsand 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-sdkmodule 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. ↩︎