--- title: Cloudflare pagination_prev: demos/local/index pagination_next: demos/extensions/index --- import current from '/version.js'; import CodeBlock from '@theme/CodeBlock'; [Cloudflare](https://www.cloudflare.com/) is a cloud services platform which includes "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 Cloudflare offerings: - ["Cloudflare Workers"](#cloudflare-workers) explores the serverless computing offering. The demo creates a JavaScript function that can process user-submitted files and generate spreadsheets. - ["Cloudflare R2"](#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](/docs/getting-started/installation/nodejs) 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 ```ts export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { const data = await request.formData() // const data = await request.json() if you are receiving a json request //... }, }; ``` ### Reading Data The SheetJS `read` method[^4] can read ArrayBuffer objects and generate SheetJS workbook objects[^5] which can be processed with other API functions. For example, a handler can use `sheet_to_csv`[^6] to generate CSV text: ```ts import XLSX from "xlsx"; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { 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 ```ts import XLSX from "xlsx"; export default { async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise { 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. ::: 1) If you do not have an account, create a new account[^7]. ### Setting up the Project and Testing [The Cloudflare Docs provide a simple step by step guide to setup, develop, test, build and deploy your project](https://developers.cloudflare.com/workers/get-started/guide/) ## Cloudflare R2 Due to R2's S3 compatability, the main NodeJS module for Cloudflare R2 is actually the AWS S3 SDK `@aws-sdk/client-s3`[^8]. The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be required in NodeJS scripts. :::note pass As the time of writing, Cloudflare R2 is not 100% compatible with the S3 API, please refer to the [S3 API Compatibility section of the official Cloudflare R2 Docs](https://developers.cloudflare.com/r2/api/s3/api/) to know more about what S3 Features are and are not supported. ::: ### Connecting to R2 The `@aws-sdk/client-s3` module exports a class `S3Client` that performs the connection. The function expects an options object that includes a region, credentials and in the case of R2 an endpoint. this client is used to interact with R2. ```ts import { S3Client } from "@aws-sdk/client-s3"; /* credentials */ const accessKeyId = "...", secretAccessKey = "..."; /* file location */ const Bucket = "...", Key = "pres.numbers"; /* connect to s3 account */ const Cloudflare = require('Cloudflare-sdk'); const s3 = new S3Client({ region: "REGION", //For cloudflare, if the cloudflare region is Auto then you put "auto" credentials: { accessKeyId, secretAccessKey }, endpoint: 'R2-ENDPOINT' //Note that the cloudflare dashboard will include the bucket prefix to the endpoint //Make sure the endpoint ends with .r2.cloudflarestorage.com not .r2.cloudflarestorage.com/bucket-name }); ``` ### Downloading Data #### Fetching Files from R2 The S3 SDK's client mentioned above when instantiated does needs to be fed commands through its ```.send()``` method to interact with R2. ```ts import { GetObjectCommand, S3Client } from "@aws-sdk/client-s3"; /* ... Client instantiation code from before ... ... */ const command = new GetObjectCommand({ Bucket: 'bucket-name', Key: 'key' }) //Create the command object, we are using GetObjectCommand to fetch an item from R2 const data = await client.send(command); //Send the command const bytes = await data.Body?.transformToByteArray(); //After receiving the item, transform it to a byte array const wb = XLSX.read(bytes); //Use SheetJS as normal const first_ws = wb.Sheets[wb.SheetNames[0]]; const csv = XLSX.utils.sheet_to_csv(first_ws); ``` ### Uploading Data The SheetJS `write` method[^9] with the option `type: "buffer"` will generate NodeJS Buffers. `R2` 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 R2: Here we are using the PutObjectCommand object to upload the data written by `write` into the R2 bucket ```js import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3"; /* ... Client instantiation code from before ... ... */ /* 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"}); const command = new PutObjectCommand({ Bucket: 'bucket-name', Key: 'key', Body }) await client.send(command); ``` ### R2 Demo :::note pass At the time of writing, the Cloudflare Free Tier included 10GB of Cloudflare R2 with 1 million Class A operations and 10 million Class B operations per month Please visit the [official pricing model for R2 for more info](https://developers.cloudflare.com/r2/pricing/) ::: [^1]: See ["Node.js compatibility"](https://developers.cloudflare.com/workers/runtime-apis/nodejs/) in the Cloudflare documentation [^2]: See ["Get started guide"](https://developers.cloudflare.com/workers/get-started/guide/#1-create-a-new-worker-project) [^3]: [Wrangler documentation](https://developers.cloudflare.com/workers/wrangler/) [^4]: See [`read` in "Reading Files"](/docs/api/parse-options) [^5]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) for more details. [^6]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) [^7]: Registering for a free account [on the Cloudflare Free Tier](https://dash.cloudflare.com/sign-up). [^8]: The `@aws-sdk/client-s3` module is distributed [on the public NPM registry](https://www.npmjs.com/package/@aws-sdk/client-s3) [^9]: See [`write` in "Writing Files"](/docs/api/write-options) [^14]: Registering for a free account [on the Cloudflare Free Tier](https://Cloudflare.amazon.com/free/) requires a valid phone number and a valid credit card.