esbuild-plugin

This commit is contained in:
SheetJS 2023-10-21 07:15:28 -04:00
parent 3ab0c1ab67
commit aeb932e1d0
8 changed files with 715 additions and 210 deletions

@ -25,7 +25,7 @@ bundle with ESBuild for browser use.
- ["NodeJS"](#nodejs) explores how to import SheetJS libraries in a script and
bundle with ESBuild for NodeJS use.
:::info pass
:::note pass
This demo focuses on integration details with the ESBuild bundler.
@ -34,6 +34,13 @@ The tutorial covers SheetJS library usage.
:::
:::info pass
The [ESBuild section of the Content demo](/docs/demos/static/esbuild) covers
loaders. They are ideal for static sites pulling data from sheets at build time.
:::
:::note
This demo was last tested on 2023 October 19 against esbuild `0.19.5`

@ -0,0 +1,151 @@
---
title: Bundling Sheets with Browserify
sidebar_label: Browserify
pagination_prev: demos/index
pagination_next: demos/grid/index
sidebar_position: 9
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
[Browserify](https://browserify.org/) is a module bundler.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses Browserify and SheetJS to export data. We'll explore how to add
SheetJS to a site using Browserify and how to export data to spreadsheets.
:::note
This demo was last tested on 2023 October 21 against Browserify `17.0.0`
:::
## Integration Details
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
installation with Yarn and other package managers.
After installing the SheetJS module in a Browserify project, `require`
expressions can load relevant parts of the library.
```js
var XLSX = require("xlsx");
// ... use XLSX ...
```
Browserify can also process `require` expressions in Web Worker scripts.
## Complete Example
0) Initialize a new project:
```bash
mkdir sheetjs-browserify
cd sheetjs-browserify
npm init -y
```
1) Install the tarball 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) Save the following to `index.js`:
```js title="index.js"
// highlight-next-line
const { utils, version, writeFileXLSX } = require('xlsx');
document.getElementById("xport").addEventListener("click", function() {
/* fetch JSON data and parse */
var url = "https://sheetjs.com/data/executive.json";
fetch(url).then(function(res) { return res.json(); }).then(function(raw_data) {
/* filter for the Presidents */
var prez = raw_data.filter(function(row) { return row.terms.some(function(term) { return term.type === "prez"; }); });
/* sort by first presidential term */
prez.forEach(function(row) {
row.start = row.terms.find(function(term) {
return term.type === "prez";
}).start
});
prez.sort(function(l,r) { return l.start.localeCompare(r.start); });
/* flatten objects */
var rows = prez.map(function(row) { return {
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}; });
/* generate worksheet and workbook */
var worksheet = utils.json_to_sheet(rows);
var workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
utils.sheet_add_aoa(worksheet, [["Name", "Birthday"]], { origin: "A1" });
/* calculate column width */
var max_width = rows.reduce(function(w, r) { return Math.max(w, r.name.length); }, 10);
worksheet["!cols"] = [ { wch: max_width } ];
/* create an XLSX file and try to save to Presidents.xlsx */
writeFileXLSX(workbook, "Presidents.xlsx");
});
});
```
3) Bundle the scripts:
```bash
npx browserify app.js > browserify.js
```
4) Spin up a local web server:
```bash
npx http-server
```
5) Create a small HTML page that loads the script. Save to `index.html`:
```html title="index.html"
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<h1>SheetJS Presidents Demo</h1>
<button id="xport">Click here to export</button>
<script src="./index.min.js"></script>
</body>
</html>
```
6) Start a local HTTP server and go to `http://localhost:8080/`
```bash
npx http-server .
```
Click on "Click here to export" to generate a file.

@ -0,0 +1,186 @@
---
title: Bundling Sheets with SWC
sidebar_label: SWC spack
pagination_prev: demos/index
pagination_next: demos/grid/index
sidebar_position: 21
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
SWC[^1] is a JS toolchain. SWC provides `spack` (formally called "swcpack") for
bundling scripts.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses `spack` and SheetJS to export data. We'll explore how to bundle
SheetJS in a site using `spack` and how to export data to spreadsheets.
:::note
This demo was last tested on 2023 October 20 against SWC 1.2.246
:::
## Integration Details
[The "Frameworks" section](/docs/getting-started/installation/frameworks) covers
installation with Yarn and other package managers.
After installing the SheetJS module in a SWC `spack` project, `import`
statements can load relevant parts of the library.
Projects that import data will use methods such as `read`[^2] to parse workbooks
and `sheet_to_json`[^3] to generate usable data from files. As `sheet_to_json`
is part of the `utils` object, the required import is:
```js
import { read, utils } from 'xlsx';
```
Projects that export data will use methods such as `json_to_sheet`[^4] to
generate worksheets and `writeFile`[^5] to export files. As `json_to_sheet` is
part of the `utils` object, the required import is:
```js
import { utils, writeFile } from 'xlsx';
```
:::warning pass
When this demo was tested against the latest version, `spack` crashed:
```
thread '<unnamed>' panicked at 'cannot access a scoped thread local variable without calling `set` first',
```
Until the bug is fixed, it is strongly recommended to use `@swc/core@1.2.246`.
:::
## Complete Example
0) Initialize a new project:
```bash
mkdir sheetjs-spack
cd sheetjs-spack
npm init -y
```
1) Install the dependencies 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`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
</Tabs>
:::note pass
The `regenerator-runtime` dependency is used for transpiling `fetch` and is not
required if the interface code does not use `fetch` or Promises.
:::
2) Save the following to `index.js`:
```js title="index.js"
import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/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 = utils.json_to_sheet(rows);
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
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.xlsx */
writeFileXLSX(workbook, "Presidents.xlsx");
});
```
3) Create an `spack.config.js` config file:
```js title="spack.config.js"
module.exports = ({
entry: {
'web': __dirname + '/index.js',
},
output: {
path: __dirname + '/lib'
},
module: {},
});
```
4) Build for production:
```bash
npx spack
```
This command will create the script `lib/web.js`
5) Create a small HTML page that loads the generated script:
```html title="index.html"
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<h1>SheetJS Presidents Demo</h1>
<button id="xport">Click here to export</button>
<script src="lib/web.js"></script>
</body>
</html>
```
6) Start a local HTTP server, then go to `http://localhost:8080/`
```bash
npx http-server
```
Click on "Click here to export" to generate a file.
[^1]: See ["Bundling Configuration"](https://swc.rs/docs/configuration/bundling) in the SWC documentation for more details.
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^3]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)
[^4]: See [`json_to_sheet` in "Utilities"](/docs/api/utilities/array#array-of-objects-input)
[^5]: See [`writeFile` in "Writing Files"](/docs/api/write-options)

@ -35,84 +35,9 @@ The following tools are covered in separate pages:
</li>);
})}</ul>
## Browserify
`browserify` is compatible with the library and should "just work" with the
`require` form in a main page or in a web worker:
```js
var XLSX = require("xlsx");
// ... use XLSX ...
```
[After installing the NodeJS module](/docs/getting-started/installation/nodejs),
bundling is straightforward:
```bash
browserify app.js > browserify.js
uglifyjs browserify.js > browserify.min.js
```
Web Worker scripts can be bundled using the same approach.
<details><summary><b>Complete Example</b> (click to show)</summary>
:::note
This demo was last tested on 2023 May 07 against Browserify `17.0.0`
:::
1) Install the tarball 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) Download the following files:
- [`app.js`](pathname:///browserify/app.js)
- [`index.html`](pathname:///browserify/index.html)
- [`xlsxworker.js`](pathname:///browserify/xlsxworker.js)
```bash
curl -LO https://docs.sheetjs.com/browserify/app.js
curl -LO https://docs.sheetjs.com/browserify/index.html
curl -LO https://docs.sheetjs.com/browserify/xlsxworker.js
```
3) Bundle the scripts:
```bash
npx browserify app.js > browserify.js
npx browserify xlsxworker.js > worker.js
```
4) Spin up a local web server:
```bash
npx http-server
```
5) Access the site `http://localhost:8080/` and use the file input element to
select a spreadsheet.
</details>
#### Browserify
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/browserify)**
## Bun
@ -312,7 +237,7 @@ click the "Click to Export!" button to generate a file.
</details>
## RequireJS
#### RequireJS
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/requirejs)**
@ -405,7 +330,6 @@ npx rollup index.js --plugin @rollup/plugin-node-resolve --file bundle.js --form
</html>
```
5) Start a local HTTP server, then go to `http://localhost:8080/`
```bash
@ -521,135 +445,9 @@ Click on "Click here to export" to generate a file.
</details>
## SWC
#### SWC
SWC provides `spack` for bundling scripts.
:::warning pass
When this demo was last tested, there was a bug affecting 1.2.247 and 1.3 . It
is strongly recommended to use `@swc/core@1.2.245` until the bug is fixed.
:::
<details><summary><b>Complete Example</b> (click to show)</summary>
:::note
This demo was last tested on 2023 May 07 against SWC 1.2.246
:::
1) Install the dependencies 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`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
<TabItem value="pnpm" label="pnpm">
<CodeBlock language="bash">{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
<TabItem value="yarn" label="Yarn" default>
<CodeBlock language="bash">{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
</CodeBlock>
</TabItem>
</Tabs>
:::note pass
The `regenerator-runtime` dependency is used for transpiling `fetch` and is not
required if the interface code does not use `fetch` or Promises.
:::
2) Save the following to `index.js`:
```js title="index.js"
import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", async() => {
/* fetch JSON data and parse */
const url = "https://sheetjs.com/data/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 = utils.json_to_sheet(rows);
const workbook = utils.book_new();
utils.book_append_sheet(workbook, worksheet, "Dates");
/* fix headers */
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.xlsx */
writeFileXLSX(workbook, "Presidents.xlsx");
});
```
3) Create an `spack.config.js` config file:
```js title="spack.config.js"
const { config } = require('@swc/core/spack');
module.exports = ({
entry: {
'web': __dirname + '/index.js',
},
output: {
path: __dirname + '/lib'
},
module: {},
});
```
4) Build for production:
```bash
npx spack
```
This command will create the script `lib/web.js`
5) Create a small HTML page that loads the generated script:
```html title="index.html"
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<h1>SheetJS Presidents Demo</h1>
<button id="xport">Click here to export</button>
<script src="lib/web.js"></script>
</body>
</html>
```
6) Start a local HTTP server, then go to `http://localhost:8080/`
```bash
npx http-server
```
Click on "Click here to export" to generate a file.
</details>
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/swcpack)**
#### SystemJS

@ -0,0 +1,361 @@
---
title: Building Sheets with ESBuild
sidebar_label: ESBuild
pagination_prev: demos/net/index
pagination_next: demos/mobile/index
sidebar_custom_props:
type: bundler
---
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
[ESBuild](https://esbuild.github.io/) is a modern build tool for generating
static sites. It has a robust JavaScript-powered plugin system[^1]
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses ESBuild and SheetJS to pull data from a spreadsheet and display
the content in an HTML table. We'll explore how to load SheetJS in a ESBuild
loader and generate data for use in webpages.
The ["Demo"](#demo) creates a complete website powered by a XLSX spreadsheet.
:::info pass
This demo covers static asset imports. For processing files in the browser, the
["Bundlers" demo](/docs/demos/frontend/bundler/esbuild) includes an example of
importing the SheetJS library in a browser script.
:::
## ESBuild Loader
ESBuild supports custom loader plugins. The loader receives an absolute path to
the spreadsheet on the filesystem.
The [SheetJS NodeJS module](/docs/getting-started/installation/nodejs) can be
imported from ESBuild loader plugins.
:::info pass
ESBuild loader plugins use ECMAScript Modules. The plugin ultimately receives
raw paths to files. [`fs`](/docs/getting-started/installation/nodejs#esm-import)
must be manually imported:
```js
import * as XLSX from 'xlsx';
/* load 'fs' for readFile and writeFile support */
import * as fs from 'fs';
XLSX.set_fs(fs);
```
:::
The following diagram depicts the workbook waltz:
```mermaid
flowchart LR
subgraph ESBuild Custom Plugin in build.mjs
file[(workbook\nfile)]
wb(((SheetJS\nWorkbook)))
aoo(array of\nobjects)
end
html{{HTML\nTABLE}}
file --> |`readFile`\n\n| wb
wb --> |`sheet_to_json`\n\n| aoo
aoo --> |app.js\nfrontend code| html
```
### ESBuild Config
Plugins can be referenced in the `plugins` array of the build config object:
```js title="build.mjs (structure)"
import * as esbuild from 'esbuild'
// highlight-next-line
let sheetjsPlugin = {
name: 'sheetjs',
setup(build) {
// ...
}
};
await esbuild.build({
entryPoints: ['app.js'],
bundle: true,
outfile: 'out.js',
// highlight-next-line
plugins: [sheetjsPlugin],
})
```
### Registering File Extensions
The `setup` method receives the build options. Handlers for custom files should
be added using `build.onLoad`.
The first argument to `onLoad` is a configuration object. The `filter` property
is expected to be a regular expression. The following regular expression matches
NUMBERS, XLSX, XLS, and XLSB files:
```js
const EXTS = /.(numbers|xlsx|xls|xlsb)$/;
```
The second argument to `onLoad` is a callback that receives an arguments object.
The `path` property of the object is the absolute path to the file.
```js
setup(build) {
build.onLoad({ filter: EXTS }, (args) => {
const path = args.path;
// ...
});
},
```
### SheetJS Operations
The SheetJS `readFile` method[^2] will directly read the file on the filesystem.
The return value is a SheetJS workbook object[^3].
The loader in this demo will parse the workbook, pull the first worksheet, and
generate an array of row objects using the `sheet_to_json` method[^4].
:::caution pass
JSON does not natively support Dates! `JSON.stringify` will generate strings.
Through a clever workaround, it is possible to encode dates separately and
recover the Date objects in the generated code module.
:::
```js
import * as XLSX from 'xlsx';
import * as fs from 'fs';
XLSX.set_fs(fs);
/* plugin */
let sheetjsPlugin = {
name: 'sheetjs',
setup(build) {
/* match NUMBERS, XLSX, XLS, and XLSB files */
const EXTS = /.(numbers|xlsx|xls|xlsb)$/;
/* this method will be called once for each referenced file */
build.onLoad({ filter: EXTS }, (args) => {
/* parse file from filesystem */
const wb = XLSX.readFile(args.path);
/* get first worksheet */
const ws = wb.Sheets[wb.SheetNames[0]];
/* workaround for JSON limitation */
Date.prototype.toJSON2 = Date.prototype.toJSON;
Date.prototype.toJSON = function() { return {d:this.toISOString()}; };
/* generate row objects */
const data = XLSX.utils.sheet_to_json(ws);
/* generate final module code */
const res = JSON.stringify(data);
Date.prototype.toJSON = Date.prototype.toJSON2;
const contents = `const data = ${res};
data.forEach(row => {
Object.keys(row).forEach(k => {
if(row[k]?.d) row[k] = new Date(row[k].d);
})
});
export default data;`
return { contents, loader: 'js' };
});
},
};
```
### Asset Imports
Spreadsheets can be imported using the plugin. Assuming `pres.xlsx` is stored
in the same folder as the script, `./pres.xlsx` will be a data module:
```js title="src/index.js"
import data from './pres.xlsx';
/* `data` is an array of objects from data/pres.xlsx */
const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
data.map((row) => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("") +
"</table>";
document.body.appendChild(elt);
```
## Demo
:::note
This demo was last tested on 2023 October 21 against ESBuild 0.19.5
:::
### Initial Setup
0) Create a new skeleton project:
```bash
mkdir sheetjs-esb
cd sheetjs-esb
npm init -y
npm i --save esbuild@0.19.5
```
1) Install the SheetJS NodeJS module:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
2) Save the following to `index.html`:
```html title="index.html"
<!DOCTYPE html>
<html>
<head>
<title>SheetJS + ESBuild</title>
</head>
<body>
<script src="out.js"></script>
</body>
</html>
```
3) Save the following to `app.js`:
```js title="app.js"
import data from './pres.numbers'
const elt = document.createElement('div');
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" +
data.map((row) => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("") +
"</table>";
document.body.appendChild(elt);
```
4) Save the following to `build.mjs`:
```js title="build.mjs"
import * as esbuild from 'esbuild'
import * as XLSX from 'xlsx';
import * as fs from 'fs';
XLSX.set_fs(fs);
let sheetjsPlugin = {
name: 'sheetjs',
setup(build) {
/* match NUMBERS, XLSX, XLS, and XLSB files */
const EXTS = /.(numbers|xlsx|xls|xlsb)$/;
/* this method will be called once for each referenced file */
build.onLoad({ filter: EXTS }, (args) => {
/* parse file from filesystem */
const wb = XLSX.readFile(args.path);
/* get first worksheet */
const ws = wb.Sheets[wb.SheetNames[0]];
/* workaround for JSON limitation */
Date.prototype.toJSON2 = Date.prototype.toJSON;
Date.prototype.toJSON = function() { return {d:this.toISOString()}; };
/* generate row objects */
const data = XLSX.utils.sheet_to_json(ws);
/* generate final module code */
const res = JSON.stringify(data);
Date.prototype.toJSON = Date.prototype.toJSON2;
const contents = `const data = ${res};
data.forEach(row => {
Object.keys(row).forEach(k => {
if(row[k]?.d) row[k] = new Date(row[k].d);
})
});
export default data;`
return { contents, loader: 'js' };
});
},
};
await esbuild.build({
entryPoints: ['app.js'],
bundle: true,
outfile: 'out.js',
plugins: [sheetjsPlugin],
});
```
5) Download <https://sheetjs.com/pres.numbers> and save to the project folder:
```bash
curl -LO https://sheetjs.com/pres.numbers
```
### Static Site Test
6) Build the site:
```bash
node build.mjs
```
The final script will be saved to `out.js`
7) Start a local web server to host the project folder:
```bash
npx http-server .
```
The command will print a list of URLs.
8) Open one of the URLs printed in the previous step (`http://localhost:8080`)
and confirm that the same data is displayed.
To verify that the data was added to the page, append `out.js` to the URL
(`http://localhost:8080/out.js`) and view the source. The source will include
president names. It will not include SheetJS library references!
In the last test, the generated source looked like the following snippet
```js title="out.js"
(() => {
// pres.numbers
var data = [{ "Name": "Bill Clinton", "Index": 42 }, /* ... more data */];
data.forEach((row) => {
Object.keys(row).forEach((k) => {
if (row[k]?.d)
row[k] = new Date(row[k].d);
});
});
var pres_default = data;
// app.js
var elt = document.createElement("div");
elt.innerHTML = "<table><tr><th>Name</th><th>Index</th></tr>" + pres_default.map((row) => `<tr>
<td>${row.Name}</td>
<td>${row.Index}</td>
</tr>`).join("") + "</table>";
document.body.appendChild(elt);
})();
```
[^1]: See ["Plugins"](https://esbuild.github.io/plugins/) in the ESBuild documentation.
[^2]: See [`readFile` in "Reading Files"](/docs/api/parse-options)
[^3]: See ["Workbook Object"](/docs/csf/book)
[^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output)

@ -125,7 +125,7 @@ This demo was tested in the following deployments:
| V8 Version | Platform | OS Version | Compiler | Date |
|:--------------|:-------------|:--------------|:-----------------|:-----------|
| `11.8.82` | `darwin-x64` | macOS 13.5.1 | `clang 14.0.3` | 2023-08-26 |
| `11.8.82` | `darwin-arm` | macOS 13.5.1 | `clang 14.0.3` | 2023-08-26 |
| `12.0.175` | `darwin-arm` | macOS 14.0 | `clang 15.0.0` | 2023-10-20 |
| `11.8.82` | `win10-x64` | Windows 10 | `CL 19.37.32822` | 2023-08-26 |
| `12.0.72` | `linux-x64` | HoloOS 3.4.11 | `gcc 12.2.0` | 2023-10-11 |
| `11.8.82` | `linux-arm` | Debian 11 | `gcc 10.2.1` | 2023-09-26 |

@ -115,7 +115,7 @@ This demo was tested in the following deployments:
| Architecture | Date |
|:-------------|:-----------|
| `darwin-x64` | 2023-08-31 |
| `darwin-arm` | 2023-07-05 |
| `darwin-arm` | 2023-10-20 |
| `win10-x64` | 2023-08-31 |
| `win11-arm` | 2023-09-26 |
| `linux-x64` | 2023-10-11 |

@ -134,6 +134,8 @@ This demo was tested in the following deployments:
| `darwin-x64` | `a588e49` | 2023-09-22 |
| `linux-x64` | `a588e49` | 2023-10-11 |
:::
:::note pass
While applications should link against the official libraries, the standalone tool