docusaurus

This commit is contained in:
SheetJS 2022-05-15 23:26:04 -04:00
parent 34f4c09cac
commit 6449ecc35e
70 changed files with 9054 additions and 4579 deletions

@ -5,6 +5,7 @@ js-xlsx
xls
xlsb
xlsx
docs.sheetjs.com
# Excel-related terms
A1-style
@ -48,6 +49,7 @@ NPM
Nuxt
PhantomJS
Photoshop
ReactJS
Redis
RequireJS
Rollup
@ -58,6 +60,7 @@ VueJS
WebKit
WebSQL
WK_
axios
iOS
iWork
nodejs

@ -1,3 +1,9 @@
.PHONY: build
build:
cd docz; pnpm build; cd ..
rm -rf docs
mv docz/build/ docs
.PHONY: index
index: readme ## Rebuild site
sed -i .bak 's/](d/](https:\/\/github.com\/SheetJS\/SheetJS\/tree\/master\/d/g' README.md
@ -21,7 +27,7 @@ formats.png legend.png: %.png: misc/%.svg
node misc/coarsify.js misc/$*.svg misc/$*.svg.svg
npx svgexport misc/$*.svg.svg $@ 0.5x
MDLINT=README.md
MDLINT=README.md $(wildcard docz/*.md*) $(wildcard docz/docs/*.md*) $(wildcard docz/docs/*/*.md*)
.PHONY: mdlint
mdlint: $(MDLINT) ## Check markdown documents
npx alex $^

4580
README.md

File diff suppressed because it is too large Load Diff

20
docz/.gitignore vendored Normal file

@ -0,0 +1,20 @@
# Dependencies
/node_modules
# Production
/build
# Generated files
.docusaurus
.cache-loader
# Misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

3
docz/README.md Normal file

@ -0,0 +1,3 @@
# docs.sheetjs.com
<https://docs.sheetjs.com/>

3
docz/babel.config.js Normal file

@ -0,0 +1,3 @@
module.exports = {
presets: [require.resolve('@docusaurus/core/lib/babel/preset')],
};

@ -0,0 +1,12 @@
---
slug: first-blog-post
title: First Blog Post
authors:
name: Gao Wei
title: Docusaurus Core Team
url: https://github.com/wgao19
image_url: https://github.com/wgao19.png
tags: [hola, docusaurus]
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

@ -0,0 +1,44 @@
---
slug: long-blog-post
title: Long Blog Post
authors: endi
tags: [hello, docusaurus]
---
This is the summary of a very long blog post,
Use a `<!--` `truncate` `-->` comment to limit blog post size in the list view.
<!--truncate-->
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet

@ -0,0 +1,20 @@
---
slug: mdx-blog-post
title: MDX Blog Post
authors: [slorber]
tags: [docusaurus]
---
Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/).
:::tip
Use the power of React to create interactive blog posts.
```js
<button onClick={() => alert('button clicked!')}>Click me!</button>
```
<button onClick={() => alert('button clicked!')}>Click me!</button>
:::

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

@ -0,0 +1,25 @@
---
slug: welcome
title: Welcome
authors: [slorber, yangshun]
tags: [facebook, hello, docusaurus]
---
[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog).
Simply add Markdown files (or folders) to the `blog` directory.
Regular blog authors can be added to `authors.yml`.
The blog post date can be extracted from filenames, such as:
- `2019-05-30-welcome.md`
- `2019-05-30-welcome/index.md`
A blog post folder can be convenient to co-locate blog post images:
![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg)
The blog supports tags as well!
**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config.

17
docz/blog/authors.yml Normal file

@ -0,0 +1,17 @@
endi:
name: Endilie Yacop Sucipto
title: Maintainer of Docusaurus
url: https://github.com/endiliey
image_url: https://github.com/endiliey.png
yangshun:
name: Yangshun Tay
title: Front End Engineer @ Facebook
url: https://github.com/yangshun
image_url: https://github.com/yangshun.png
slorber:
name: Sébastien Lorber
title: Docusaurus maintainer
url: https://sebastienlorber.com
image_url: https://github.com/slorber.png

@ -0,0 +1,112 @@
---
sidebar_position: 1
sidebar_custom_props:
summary: Classic pages with simple <script> tags
---
import current from '/version.js';
# Standalone Browser Scripts
Each standalone release script is available at <https://cdn.sheetjs.com/>.
<div>The current version is {current} and can be referenced as follows:</div>
<pre><code parentName="pre" {...{"className": "language-html"}}>{`\
<!-- use version ${current} -->
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js"></script>`}
</code></pre>
The `latest` tag references the latest version and updates with each release:
```html
<!-- use the latest version -->
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
```
**For production use, scripts should be downloaded and added to a public folder
alongside other scripts.**
<details>
<summary><b>Download using Bower</b> (click to show)</summary>
[Bower](https://bower.io/) plays nice with the CDN tarballs:
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ npx bower install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
Bower will place the standalone scripts in `bower_components/js-xlsx/dist/`
</details>
<details>
<summary><b>Browser builds</b> (click to show)</summary>
The complete single-file version is generated at `dist/xlsx.full.min.js`
`dist/xlsx.core.min.js` omits codepage library (no support for XLS encodings)
A slimmer build is generated at `dist/xlsx.mini.min.js`. Compared to full build:
- codepage library skipped (no support for XLS encodings)
- no support for XLSB / XLS / Lotus 1-2-3 / SpreadsheetML 2003 / Numbers
- node stream utils removed
These scripts are also available on the CDN:
<pre><code parentName="pre" {...{"className": "language-html"}}>{`\
<!-- use xlsx.mini.min.js from version ${current} -->
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js"></script>`}
</code></pre>
</details>
<details>
<summary><b>Internet Explorer and ECMAScript 3 Compatibility</b> (click to show)</summary>
For broad compatibility with JavaScript engines, the library is written using
ECMAScript 3 language dialect as well as some ES5 features like `Array#forEach`.
Older browsers require shims to provide missing functions.
To use the shim, add the shim before the script tag that loads `xlsx.js`:
```html
<!-- add the shim first -->
<script type="text/javascript" src="shim.min.js"></script>
<!-- after the shim is referenced, add the library -->
<script type="text/javascript" src="xlsx.full.min.js"></script>
```
Due to SSL certificate compatibility issues, it is highly recommended to save
the Standalone and Shim scripts from <https://cdn.sheetjs.com/> and add to a
public directory in the site.
The script also includes `IE_LoadFile` and `IE_SaveFile` for loading and saving
files in Internet Explorer versions 6-9. The `xlsx.extendscript.js` script
bundles the shim in a format suitable for Photoshop and other Adobe products.
</details>
<details>
<summary><b>ECMAScript Module Imports in a SCRIPT TAG</b> (click to show)</summary>
The ECMAScript Module build is saved to `xlsx.mjs` and can be directly added to
a page with a `script` tag using `type="module"`:
<pre><code parentName="pre" {...{"className": "language-html"}}>{`\
<script type="module">
import { read, writeFileXLSX } from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
</script>`}
</code></pre>
If XLS support is required, `cpexcel.full.js` must be manually imported:
<pre><code parentName="pre" {...{"className": "language-html"}}>{`\
<script type="module">
/* load the codepage support library for extended support with older formats */
import { set_cptable } from "https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs";
import * as cptable from 'https://cdn.sheetjs.com/xlsx-${current}/package/dist/cpexcel.full.mjs';
set_cptable(cptable);
</script>`}
</code></pre>
</details>

@ -0,0 +1,54 @@
---
sidebar_position: 2
sidebar_custom_props:
summary: Angular, React, VueJS, Webpack, etc.
---
import current from '/version.js';
# Frameworks and Bundlers
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Each standalone release package is available at <https://cdn.sheetjs.com/>. The
NodeJS package is designed to be used with frameworks and bundlers. It is a
proper ECMAScript Module release which can be optimized with developer tools.
<Tabs>
<TabItem value="npm" label="npm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ npm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ yarn add --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
</Tabs>
Once installed, the library can be imported under the name `xlsx`:
```js
import { read, writeFileXLSX } from "xlsx";
```
<details>
<summary><b>XLS Codepage support</b> (click to show)</summary>
If XLS support is required, `cpexcel.full.js` must be manually imported:
```js
/* load the codepage support library for extended support with older formats */
import { set_cptable } from "xlsx";
import * as cptable from 'xlsx/dist/cpexcel.full.mjs';
set_cptable(cptable);
```
</details>

@ -0,0 +1,31 @@
---
sidebar_position: 3
sidebar_custom_props:
summary: Import ECMAScript Modules and TypeScript definitions
---
import current from '/version.js';
# Deno
Each standalone release script is available at <https://cdn.sheetjs.com/>.
Using the URL imports, `deno run` will automatically download scripts and types:
<pre><code parentName="pre" {...{"className": "language-ts"}}>{`\
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';`}
</code></pre>
<details>
<summary><b>XLS Codepage support</b> (click to show)</summary>
If XLS support is required, `cpexcel.full.js` must be manually imported:
<pre><code parentName="pre" {...{"className": "language-ts"}}>{`\
/* load the codepage support library for extended support with older formats */
import * as cptable from 'https://cdn.sheetjs.com/xlsx-${current}/package/dist/cpexcel.full.mjs';
XLSX.set_cptable(cptable);`}
</code></pre>
</details>

@ -0,0 +1,104 @@
---
sidebar_position: 4
sidebar_custom_props:
summary: Server-side and other frameworks using NodeJS modules
---
import current from '/version.js';
# NodeJS
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
Tarballs are available on <https://cdn.sheetjs.com>.
<div>Each individual version can be referenced using a similar URL pattern.
<a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a> is the URL for {current}</div>
<https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz> is a link to the latest
version and will refresh on each release.
## Installation
Tarballs can be directly installed using a package manager:
<Tabs>
<TabItem value="npm" label="npm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ npm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ pnpm install --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ yarn add --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
</Tabs>
### Vendoring
For general stability, "vendoring" modules is the recommended approach:
<div>1) Download the tarball (<code parentName="pre">xlsx-{current}.tgz</code>) for the desired version. The current
version is available at <a href={`https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}>https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz</a></div><br/>
2) Create a `vendor` subdirectory at the root of your project and move the
tarball to that folder. Add it to your project repository.
3) Install the tarball using a package manager:
<Tabs>
<TabItem value="npm" label="npm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ npm install --save file:vendor/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ pnpm install --save file:vendor/xlsx-${current}.tgz`}
</code></pre>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<pre><code parentName="pre" {...{"className": "language-bash"}}>{`\
$ yarn add --save file:vendor/xlsx-0.18.7.tgz`}
</code></pre>
</TabItem>
</Tabs>
The package will be installed and accessible as `xlsx`.
## Usage
By default, the module supports `require` and it will automatically add support
for streams and filesystem access:
```js
var XLSX = require("xlsx");
```
The module also ships with `xlsx.mjs` for use with `import`. The `mjs` version
does not automatically load native node modules, so they must be added manually:
```js
import * as XLSX from 'xlsx/xlsx.mjs';
/* load 'fs' for readFile and writeFile support */
import * as fs from 'fs';
XLSX.set_fs(fs);
/* load 'stream' for stream support */
import { Readable } from 'stream';
XLSX.stream.set_readable(Readable);
/* load the codepage support library for extended support with older formats */
import * as cpexcel from 'xlsx/dist/cpexcel.full.mjs';
XLSX.set_cptable(cpexcel);
```

@ -0,0 +1,21 @@
---
sidebar_position: 5
sidebar_custom_props:
summary: Photoshop, InDesign, and other Creative Cloud apps
---
import current from '/version.js';
# ExtendScript
Each standalone release script is available at <https://cdn.sheetjs.com/>.
`xlsx.extendscript.js` is an ExtendScript build for Photoshop and InDesign.
<div><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.extendscript.js`}>https://cdn.sheetjs.com/xlsx-{current}/package/dist/xlsx.extendscript.js</a> is the URL for {current}</div><br/>
After downloading the script, it can be directly referenced with `#include`:
```c
#include "xlsx.extendscript.js"
```

@ -0,0 +1,4 @@
{
"label": "Installation",
"position": 2
}

@ -0,0 +1,20 @@
---
hide_table_of_contents: true
---
# Installation
import DocCardList from '@theme/DocCardList';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
<https://cdn.sheetjs.com> is the primary software distribution site. Please
read the installation instructions for your use case:
<ul>{useCurrentSidebarCategory().items.map((item, index) => {
const listyle = (item.customProps?.icon) ? {
listStyleImage: `url("${item.customProps.icon}")`
} : {};
return (<li style={listyle} {...(item.customProps?.class ? {className: item.customProps.class}: {})}>
<a href={item.href}>{item.label}</a>{item.customProps?.summary && (" - " + item.customProps.summary)}
</li>);
})}</ul>

375
docz/docs/03-example.mdx Normal file

@ -0,0 +1,375 @@
---
sidebar_position: 3
---
# Complete Example
SheetJS presents a simple JS interface that works with "Array of Arrays" and
"Array of JS Objects". The API functions are building blocks that should be
combined with other JS APIs to solve problems.
The discussion focuses on the problem solving mindset. API details are covered
in other parts of the documentation.
The goal of this example is to generate a XLSB workbook of US President names
and birthdays. [Click here](#live-demo) to jump to the live demo
## Acquire Data
### Raw Data
[The raw data is available in JSON form](https://theunitedstates.io/congress-legislators/executive.json).
For convenience, it has been [mirrored here](https://sheetjs.com/executive.json)
The data result is an Array of objects. This is the data for John Adams:
```js
{
"id": { /* (data omitted) */ },
"name": {
"first": "John", // <-- first name
"last": "Adams" // <-- last name
},
"bio": {
"birthday": "1735-10-19", // <-- birthday
"gender": "M"
},
"terms": [
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "viceprez", /* (other fields omitted) */ },
{ "type": "prez", /* (other fields omitted) */ }
]
}
```
### Filtering for Presidents
The dataset includes Aaron Burr, a Vice President who was never President!
`Array#filter` creates a new array with the desired rows. A President served
at least one term with `type` set to `"prez"`. To test if a particular row has
at least one `"prez"` term, `Array#some` is another native JS function. The
complete filter would be:
```js
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
```
### Reshaping the Array
For this example, the name will be the first name combined with the last name
(`row.name.first + " " + row.name.last`) and the birthday will be the subfield
`row.bio.birthday`. Using `Array#map`, the dataset can be massaged in one call:
```js
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
```
The result is an array of "simple" objects with no nesting:
```js
[
{ name: "George Washington", birthday: "1732-02-22" },
{ name: "John Adams", birthday: "1735-10-19" },
// ... one row per President
]
```
## Create a Workbook
With the cleaned dataset, `XLSX.utils.json_to_sheet` generates a worksheet:
```js
const worksheet = XLSX.utils.json_to_sheet(rows);
```
`XLSX.utils.book_new` creates a new workbook and `XLSX.utils.book_append_sheet`
appends a worksheet to the workbook. The new worksheet will be called "Dates":
```js
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
```
## Clean up Workbook
The data is in the workbook and can be exported.
![Rough export](./img/rough.png)
There are multiple opportunities for improvement: the headers can be renamed and
the column widths can be adjusted. [SheetJS Pro](https://sheetjs.com/pro) offers
additional styling options like cell styling and frozen rows.
<details><summary><b>Changing Header Names</b> (click to show)</summary>
By default, `json_to_sheet` creates a worksheet with a header row. In this case,
the headers come from the JS object keys: "name" and "birthday".
The headers are in cells A1 and B1. `XLSX.utils.sheet_add_aoa` can write text
values to the existing worksheet starting at cell A1:
```js
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
```
</details>
<details><summary><b>Changing Column Widths</b> (click to show)</summary>
Some of the names are longer than the default column width. Column widths are
set by setting the `"!cols"` worksheet property.
The following line sets the width of column A to approximately 10 characters:
```js
worksheet["!cols"] = [ { wch: 10 } ]; // set column A width to 10 characters
```
One `Array#reduce` call over `rows` can calculate the maximum width:
```js
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
```
</details>
## Export a File
`XLSX.writeFile` creates a spreadsheet file and tries to write it to the system.
In the browser, it will try to prompt the user to download the file. In NodeJS,
it will write to the local directory.
```js
XLSX.writeFile(workbook, "Presidents.xlsb");
```
![Final export](./img/final.png)
## Live Demo
```jsx live
function Presidents() { return ( <button onClick={async () => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsb */
XLSX.writeFile(workbook, "Presidents.xlsb");
}}><b>Click to Generate file!</b></button> ); }
```
## Run the Demo Locally
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="browser" label="Browser">
Save the following script to `snippet.html` and open the page. The page must be
hosted (no `file:///` access).
<https://sheetjs.com/pres.html> is a hosted version of the page.
```html
<body>
<script src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
<script>
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsb */
XLSX.writeFile(workbook, "Presidents.xlsb");
})();
</script>
<body>
```
</TabItem>
<TabItem value="nodejs" label="NodeJS">
Install the dependencies:
```bash
$ npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
```
Save the following script to `snippet.js` and run `node snippet.js`:
```js
const XLSX = require("xlsx");
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsb */
XLSX.writeFile(workbook, "Presidents.xlsb");
})();
```
Native `fetch` support was added in NodeJS 18. For older versions of NodeJS,
the script will throw an error `fetch is not defined`. A third-party library
like `axios` presents a similar API for fetching data:
<details><summary><b>Example using axios</b> (click to show)</summary>
Install the dependencies:
```bash
$ npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz
```
The differences in the script are highlighted below.
```js
const XLSX = require("xlsx");
// highlight-next-line
const axios = require("axios");
(async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/executive.json";
// highlight-next-line
const raw_data = (await axios(url, {responseType: "json"})).data;
/* filter for the Presidents */
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* flatten objects */
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w, r) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsb */
XLSX.writeFile(workbook, "Presidents.xlsb");
})();
```
</details>
</TabItem>
<TabItem value="deno" label="Deno">
Save the following script to `snippet.ts` and run with
`deno run --allow-net --allow-write snippet.ts`:
```js
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
/* fetch JSON data and parse */
const url = "https://sheetjs.com/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter((row: any) => row.terms.some((term: any) => term.type === "prez"));
/* flatten objects */
const rows = prez.map((row: any) => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));
/* generate worksheet and workbook */
const worksheet = XLSX.utils.json_to_sheet(rows);
const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
XLSX.utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
const max_width = rows.reduce((w: number, r: any) => Math.max(w, r.name.length), 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsb */
XLSX.writeFile(workbook, "Presidents.xlsb");
```
</TabItem>
</Tabs>

@ -0,0 +1,67 @@
---
sidebar_position: 1
---
# Roadmap
Most scenarios involving spreadsheets and data can be divided into 5 parts:
1) **Acquire Data**: Data may be stored anywhere: local or remote files,
databases, HTML TABLE, or even generated programmatically in the web browser.
2) **Extract Data**: For spreadsheet files, this involves parsing raw bytes to
read the cell data. For general JS data, this involves reshaping the data.
3) **Process Data**: From generating summary statistics to cleaning data
records, this step is the heart of the problem.
4) **Package Data**: This can involve making a new spreadsheet or serializing
with `JSON.stringify` or writing XML or simply flattening data for UI tools.
5) **Release Data**: Spreadsheet files can be uploaded to a server or written
locally. Data can be presented to users in an HTML TABLE or data grid.
A common problem involves generating a valid spreadsheet export from data stored
in an HTML table. In this example, an HTML TABLE on the page will be scraped,
a row will be added to the bottom with the date of the report, and a new file
will be generated and downloaded locally. `XLSX.writeFile` takes care of
packaging the data and attempting a local download:
```js
// Acquire Data (reference to the HTML table)
var table_elt = document.getElementById("my-table-id");
// Extract Data (create a workbook object from the table)
var workbook = XLSX.utils.table_to_book(table_elt);
// Process Data (add a new row)
var ws = workbook.Sheets["Sheet1"];
XLSX.utils.sheet_add_aoa(ws, [["Created "+new Date().toISOString()]], {origin:-1});
// Package and Release Data (`writeFile` tries to write and save an XLSB file)
XLSX.writeFile(workbook, "Report.xlsb");
```
This library tries to simplify steps 2 and 4 with functions to extract useful
data from spreadsheet files (`read` / `readFile`) and generate new spreadsheet
files from data (`write` / `writeFile`). Additional utility functions like
`table_to_book` work with other common data sources like HTML tables.
This documentation and various demo projects cover a number of common scenarios
and approaches for steps 1 and 5.
Utility functions help with step 3.
## Highlights
["Data Import"](../solutions/input) describes solutions for common data import
scenarios.
["Data Export"](../solutions/output) describes solutions for common data export
scenarios.
["Data Processing"](../solutions/processing) describes solutions for common
workbook processing and manipulation scenarios.
["Utility Functions"](../api/utilities) details utility functions for
translating JSON Arrays and other common JS structures into worksheet objects.

@ -0,0 +1,37 @@
---
sidebar_position: 2
hide_table_of_contents: true
---
# Zen of SheetJS
SheetJS design and development is guided by a few key principles.
### Data processing should fit in any workflow
The library does not impose a separate lifecycle. It fits nicely in websites
and apps built using any framework. The plain JS data objects play nice with
Web Workers and future APIs.
### JavaScript is a powerful language for data processing
The ["Common Spreadsheet Format"](../csf/general) is a simple object
representation of the core concepts of a workbook. The various functions in the
library provide low-level tools for working with the object.
For friendly JS processing, there are utility functions for converting parts of
a worksheet to/from an Array of Arrays. The [Complete example](../03-example.mdx)
combines powerful JS Array methods with a network request library to download
data, select the information we want and create a workbook file:
### File formats are implementation details
The parser covers a wide gamut of common spreadsheet file formats to ensure that
"HTML-saved-as-XLS" files work as well as actual XLS or XLSX files.
The writer supports a number of common output formats for broad compatibility
with the data ecosystem.
To the greatest extent possible, data processing code should not have to worry
about the specific file formats involved.

@ -0,0 +1,50 @@
---
sidebar_position: 3
hide_table_of_contents: true
---
# Demo Projects
The demo projects include small runnable examples and short explainers.
### Frameworks and APIs
- [`Angular.JS`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular/)
- [`Angular 2+ and Ionic`](https://github.com/SheetJS/SheetJS/tree/master/demos/angular2/)
- [`Knockout`](https://github.com/SheetJS/SheetJS/tree/master/demos/knockout/)
- [`Meteor`](https://github.com/SheetJS/SheetJS/tree/master/demos/meteor/)
- [`React, React Native and NextJS`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/)
- [`VueJS, WeeX, and NuxtJS`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/)
- [`XMLHttpRequest and fetch`](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/)
- [`NodeJS Server-Side Processing`](https://github.com/SheetJS/SheetJS/tree/master/demos/server/)
- [`Databases and Key/Value Stores`](https://github.com/SheetJS/SheetJS/tree/master/demos/database/)
- [`Typed Arrays and Math`](https://github.com/SheetJS/SheetJS/tree/master/demos/array/)
### Front-End UI Components
- [`canvas-datagrid`](https://github.com/SheetJS/SheetJS/tree/master/demos/datagrid/)
- [`x-spreadsheet`](https://github.com/SheetJS/SheetJS/tree/master/demos/xspreadsheet/)
- [`react-data-grid`](https://github.com/SheetJS/SheetJS/tree/master/demos/react/modify/)
- [`vue3-table-light`](https://github.com/SheetJS/SheetJS/tree/master/demos/vue/modify/)
### Platforms and Integrations
- [`Deno`](https://github.com/SheetJS/SheetJS/tree/master/demos/deno/)
- [`Electron`](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
- [`NW.js`](https://github.com/SheetJS/SheetJS/tree/master/demos/nwjs/)
- [`Chrome / Chromium Extension`](https://github.com/SheetJS/SheetJS/tree/master/demos/chrome/)
- [`Google Sheet export`](https://github.com/SheetJS/SheetJS/tree/master/demos/google-sheet/)
- [`ExtendScript for Adobe Apps`](https://github.com/SheetJS/SheetJS/tree/master/demos/extendscript/)
- [`Headless Browsers`](https://github.com/SheetJS/SheetJS/tree/master/demos/headless/)
- [`Other JavaScript Engines`](https://github.com/SheetJS/SheetJS/tree/master/demos/altjs/)
- [`"serverless" functions`](https://github.com/SheetJS/SheetJS/tree/master/demos/function/)
- [`Legacy Internet Explorer`](https://github.com/SheetJS/SheetJS/tree/master/demos/oldie/)
### Bundlers and Tooling
- [`browserify`](https://github.com/SheetJS/SheetJS/tree/master/demos/browserify/)
- [`fusebox`](https://github.com/SheetJS/SheetJS/tree/master/demos/fusebox/)
- [`parcel`](https://github.com/SheetJS/SheetJS/tree/master/demos/parcel/)
- [`requirejs`](https://github.com/SheetJS/SheetJS/tree/master/demos/requirejs/)
- [`rollup`](https://github.com/SheetJS/SheetJS/tree/master/demos/rollup/)
- [`systemjs`](https://github.com/SheetJS/SheetJS/tree/master/demos/systemjs/)
- [`typescript`](https://github.com/SheetJS/SheetJS/tree/master/demos/typescript/)
- [`webpack 2.x`](https://github.com/SheetJS/SheetJS/tree/master/demos/webpack/)

@ -0,0 +1,4 @@
{
"label": "Getting Started",
"position": 4
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

70
docz/docs/05-interface.md Normal file

@ -0,0 +1,70 @@
---
sidebar_position: 5
---
# Interface Summary
`XLSX` is the exposed variable in the browser and the exported node variable
`XLSX.version` is the version of the library (added by the build script).
`XLSX.SSF` is an embedded version of the [format library](https://github.com/SheetJS/ssf).
## Parsing functions
`XLSX.read(data, read_opts)` attempts to parse `data`.
`XLSX.readFile(filename, read_opts)` attempts to read `filename` and parse.
Parse options are described in the [Parsing Options](./api/parse-options) section.
## Writing functions
`XLSX.write(wb, write_opts)` attempts to write the workbook `wb`
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`.
In browser-based environments, it will attempt to force a client-side download.
`XLSX.writeFileAsync(filename, wb, o, cb)` attempts to write `wb` to `filename`.
If `o` is omitted, the writer will use the third argument as the callback.
`XLSX.stream` contains a set of streaming write functions.
Write options are described in the [Writing Options](./api/write-options) section.
## Utilities
Utilities are available in the `XLSX.utils` object and are described in the
[Utility Functions](./api/utilities) section:
**Constructing:**
- `book_new` creates an empty workbook
- `book_append_sheet` adds a worksheet to a workbook
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
- `table_to_sheet` converts a DOM TABLE element to a worksheet.
- `sheet_add_aoa` adds an array of arrays of JS data to an existing worksheet.
- `sheet_add_json` adds an array of JS objects to an existing worksheet.
**Exporting:**
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
- `sheet_to_csv` generates delimiter-separated-values output.
- `sheet_to_txt` generates UTF16 formatted text.
- `sheet_to_html` generates HTML output.
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
**Cell and cell address manipulation:**
- `format_cell` generates the text value for a cell (using number formats).
- `encode_row / decode_row` converts between 0-indexed rows and 1-indexed rows.
- `encode_col / decode_col` converts between 0-indexed columns and column names.
- `encode_cell / decode_cell` converts cell addresses.
- `encode_range / decode_range` converts cell ranges.

@ -0,0 +1,782 @@
---
sidebar_position: 1
---
# Data Import
## Parsing Workbooks
#### API
_Extract data from spreadsheet bytes_
```js
var workbook = XLSX.read(data, opts);
```
The `read` method can extract data from spreadsheet bytes stored in a JS string,
"binary string", NodeJS buffer or typed array (`Uint8Array` or `ArrayBuffer`).
_Read spreadsheet bytes from a local file and extract data_
```js
var workbook = XLSX.readFile(filename, opts);
```
The `readFile` method attempts to read a spreadsheet file at the supplied path.
Browsers generally do not allow reading files in this way (it is deemed a
security risk), and attempts to read files in this way will throw an error.
The second `opts` argument is optional. ["Parsing Options"](../api/parse-options)
covers the supported properties and behaviors.
#### Examples
Here are a few common scenarios (click on each subtitle to see the code):
<details>
<summary><b>Local file in a NodeJS server</b> (click to show)</summary>
`readFile` uses `fs.readFileSync` under the hood:
```js
var XLSX = require("xlsx");
var workbook = XLSX.readFile("test.xlsx");
```
For Node ESM, the `readFile` helper is not enabled. Instead, `fs.readFileSync`
should be used to read the file data as a `Buffer` for use with `XLSX.read`:
```js
import { readFileSync } from "fs";
import { read } from "xlsx/xlsx.mjs";
const buf = readFileSync("test.xlsx");
/* buf is a Buffer */
const workbook = read(buf);
```
</details>
<details>
<summary><b>Local file in a Deno application</b> (click to show)</summary>
`readFile` uses `Deno.readFileSync` under the hood:
```js
// @deno-types="https://deno.land/x/sheetjs/types/index.d.ts"
import * as XLSX from 'https://deno.land/x/sheetjs/xlsx.mjs'
const workbook = XLSX.readFile("test.xlsx");
```
Applications reading files must be invoked with the `--allow-read` flag. The
[`deno` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/deno/) has more examples
</details>
<details>
<summary><b>User-submitted file in a web page ("Drag-and-Drop")</b> (click to show)</summary>
For modern websites targeting Chrome 76+, `File#arrayBuffer` is recommended:
```js
// XLSX is a global from the standalone script
async function handleDropAsync(e) {
e.stopPropagation(); e.preventDefault();
const f = e.dataTransfer.files[0];
/* f is a File */
const data = await f.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
drop_dom_element.addEventListener("drop", handleDropAsync, false);
```
For maximal compatibility, the `FileReader` API should be used:
```js
function handleDrop(e) {
e.stopPropagation(); e.preventDefault();
var f = e.dataTransfer.files[0];
/* f is a File */
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
/* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */
var workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsArrayBuffer(f);
}
drop_dom_element.addEventListener("drop", handleDrop, false);
```
<https://oss.sheetjs.com/sheetjs/> demonstrates the FileReader technique.
</details>
<details>
<summary><b>User-submitted file with an HTML INPUT element</b> (click to show)</summary>
Starting with an HTML INPUT element with `type="file"`:
```html
<input type="file" id="input_dom_element">
```
For modern websites targeting Chrome 76+, `Blob#arrayBuffer` is recommended:
```js
// XLSX is a global from the standalone script
async function handleFileAsync(e) {
const file = e.target.files[0];
const data = await file.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
input_dom_element.addEventListener("change", handleFileAsync, false);
```
For broader support (including IE10+), the `FileReader` approach is recommended:
```js
function handleFile(e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var data = e.target.result;
/* reader.readAsArrayBuffer(file) -> data will be an ArrayBuffer */
var workbook = XLSX.read(e.target.result);
/* DO SOMETHING WITH workbook HERE */
};
reader.readAsArrayBuffer(file);
}
input_dom_element.addEventListener("change", handleFile, false);
```
The [`oldie` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/oldie/) shows an IE-compatible fallback scenario.
</details>
<details>
<summary><b>Fetching a file in the web browser ("Ajax")</b> (click to show)</summary>
For modern websites targeting Chrome 42+, `fetch` is recommended:
```js
// XLSX is a global from the standalone script
(async() => {
const url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
const data = await (await fetch(url)).arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
})();
```
For broader support, the `XMLHttpRequest` approach is recommended:
```js
var url = "http://oss.sheetjs.com/test_files/formula_stress_test.xlsx";
/* set up async GET request */
var req = new XMLHttpRequest();
req.open("GET", url, true);
req.responseType = "arraybuffer";
req.onload = function(e) {
var workbook = XLSX.read(req.response);
/* DO SOMETHING WITH workbook HERE */
};
req.send();
```
The [`xhr` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/xhr/) includes a longer discussion and more examples.
<http://oss.sheetjs.com/sheetjs/ajax.html> shows fallback approaches for IE6+.
</details>
<details>
<summary><b>Local file in a PhotoShop or InDesign plugin</b> (click to show)</summary>
`readFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
The specified path should be an absolute path:
```js
#include "xlsx.extendscript.js"
/* Read test.xlsx from the Documents folder */
var workbook = XLSX.readFile(Folder.myDocuments + "/test.xlsx");
```
The [`extendscript` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/extendscript/) includes a more complex example.
</details>
<details>
<summary><b>Local file in an Electron app</b> (click to show)</summary>
`readFile` can be used in the renderer process:
```js
/* From the renderer process */
var XLSX = require("xlsx");
var workbook = XLSX.readFile(path);
```
Electron APIs have changed over time. The [`electron` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
shows a complete example and details the required version-specific settings.
</details>
<details>
<summary><b>Local file in a mobile app with React Native</b> (click to show)</summary>
The [`react` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/react) includes a sample React Native app.
Since React Native does not provide a way to read files from the filesystem, a
third-party library must be used. The following libraries have been tested:
- [`react-native-file-access`](https://npm.im/react-native-file-access)
The `base64` encoding returns strings compatible with the `base64` type:
```js
import XLSX from "xlsx";
import { FileSystem } from "react-native-file-access";
const b64 = await FileSystem.readFile(path, "base64");
/* b64 is a base64 string */
const workbook = XLSX.read(b64, {type: "base64"});
```
- [`react-native-fs`](https://npm.im/react-native-fs)
The `ascii` encoding returns binary strings compatible with the `binary` type:
```js
import XLSX from "xlsx";
import { readFile } from "react-native-fs";
const bstr = await readFile(path, "ascii");
/* bstr is a binary string */
const workbook = XLSX.read(bstr, {type: "binary"});
```
</details>
<details>
<summary><b>NodeJS Server File Uploads</b> (click to show)</summary>
`read` can accept a NodeJS buffer. `readFile` can read files generated by a
HTTP POST request body parser like [`formidable`](https://npm.im/formidable):
```js
const XLSX = require("xlsx");
const http = require("http");
const formidable = require("formidable");
const server = http.createServer((req, res) => {
const form = new formidable.IncomingForm();
form.parse(req, (err, fields, files) => {
/* grab the first file */
const f = Object.entries(files)[0][1];
const path = f.filepath;
const workbook = XLSX.readFile(path);
/* DO SOMETHING WITH workbook HERE */
});
}).listen(process.env.PORT || 7262);
```
The [`server` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/server) has more advanced examples.
</details>
<details>
<summary><b>Download files in a NodeJS process</b> (click to show)</summary>
Node 17.5 and 18.0 have native support for fetch:
```js
const XLSX = require("xlsx");
const data = await (await fetch(url)).arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
```
For broader compatibility, third-party modules are recommended.
[`request`](https://npm.im/request) requires a `null` encoding to yield Buffers:
```js
var XLSX = require("xlsx");
var request = require("request");
request({url: url, encoding: null}, function(err, resp, body) {
var workbook = XLSX.read(body);
/* DO SOMETHING WITH workbook HERE */
});
```
[`axios`](https://npm.im/axios) works the same way in browser and in NodeJS:
```js
const XLSX = require("xlsx");
const axios = require("axios");
(async() => {
const res = await axios.get(url, {responseType: "arraybuffer"});
/* res.data is a Buffer */
const workbook = XLSX.read(res.data);
/* DO SOMETHING WITH workbook HERE */
})();
```
</details>
<details>
<summary><b>Download files in an Electron app</b> (click to show)</summary>
The `net` module in the main process can make HTTP/HTTPS requests to external
resources. Responses should be manually concatenated using `Buffer.concat`:
```js
const XLSX = require("xlsx");
const { net } = require("electron");
const req = net.request(url);
req.on("response", (res) => {
const bufs = []; // this array will collect all of the buffers
res.on("data", (chunk) => { bufs.push(chunk); });
res.on("end", () => {
const workbook = XLSX.read(Buffer.concat(bufs));
/* DO SOMETHING WITH workbook HERE */
});
});
req.end();
```
</details>
<details>
<summary><b>Readable Streams in NodeJS</b> (click to show)</summary>
When dealing with Readable Streams, the easiest approach is to buffer the stream
and process the whole thing at the end:
```js
var fs = require("fs");
var XLSX = require("xlsx");
function process_RS(stream, cb) {
var buffers = [];
stream.on("data", function(data) { buffers.push(data); });
stream.on("end", function() {
var buffer = Buffer.concat(buffers);
var workbook = XLSX.read(buffer, {type:"buffer"});
/* DO SOMETHING WITH workbook IN THE CALLBACK */
cb(workbook);
});
}
```
</details>
<details>
<summary><b>ReadableStream in the browser</b> (click to show)</summary>
When dealing with `ReadableStream`, the easiest approach is to buffer the stream
and process the whole thing at the end:
```js
// XLSX is a global from the standalone script
async function process_RS(stream) {
/* collect data */
const buffers = [];
const reader = stream.getReader();
for(;;) {
const res = await reader.read();
if(res.value) buffers.push(res.value);
if(res.done) break;
}
/* concat */
const out = new Uint8Array(buffers.reduce((acc, v) => acc + v.length, 0));