---
title: Bundlers
pagination_prev: demos/index
pagination_next: demos/grid/index
sidebar_position: 19
sidebar_custom_props:
skip: 1
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
SheetJS predates ECMAScript modules and most bundler tools. As best practices
have evolved, stress testing SheetJS libraries have revealed bugs in bundlers
and other tools. This demo collects various notes and provides basic examples.
:::note pass
Issues should be reported to the respective bundler projects. Typically it is
considered a bundler bug if the tool cannot properly handle JS libraries.
:::
The following tools are covered in separate pages:
## 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.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against Browserify `17.0.0`
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
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.
## Bun
`bun bun` is capable of optimizing imported libraries in `node_modules`. In
local testing, a bundled script can save tens of milliseconds per run.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against Bun `0.5.9`
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2) Save the following script to `bun.js`:
```js title="bun.js"
// highlight-next-line
import * as XLSX from 'xlsx';
// highlight-next-line
import * as fs from 'fs';
// highlight-next-line
XLSX.set_fs(fs);
/* 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 = 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.xlsx */
XLSX.writeFile(workbook, "Presidents.xlsx");
```
3) Bundle the script with `bun bun`:
```bash
bun bun bun.js
```
This procedure will generate `node_modules.bun`.
4) Run the script
```bash
bun bun.js
```
## Dojo
Integration details are included [in the "AMD" installation](/docs/getting-started/installation/amd#dojo-toolkit)
Complete Examples are included [in the "Dojo" demo](/docs/demos/frontend/legacy#dojo-toolkit)
## esbuild
The `xlsx.mjs` source file uses a subset of ES6 that `esbuild` understands and
is able to transpile for older browsers.
Both the `node` and `browser` platforms work out of the box.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against esbuild `0.17.18`
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2) Save the following to `esbrowser.js`:
```js title="esbrowser.js"
// highlight-next-line
import { utils, version, writeFileXLSX } from 'xlsx';
(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 a small HTML page that loads the script. Save to `index.html`:
```html title="index.html"
```
4) Create bundle:
```bash
npx esbuild@0.17.18 esbrowser.js --bundle --outfile=esb.browser.js
```
5) Start a local HTTP server, then go to `http://localhost:8080/`
```bash
npx http-server .
```
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2) Save the following to `esbnode.js`:
```js title="esbnode.js"
// highlight-next-line
import { set_fs, utils, version, writeFile } from 'xlsx';
// highlight-next-line
import * as fs from 'fs';
// highlight-next-line
set_fs(fs);
(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 */
writeFile(workbook, "Presidents.xlsx");
})();
```
3) Create bundle:
```bash
npx esbuild@0.17.18 esbnode.js --bundle --platform=node --outfile=esb.node.js
```
4) Run the bundle:
```bash
node esb.node.js
```
:::note pass
Bundling raw data is supported using the `binary` loader. For more advanced
content workflows, [ViteJS](/docs/demos/static/vitejs) is the recommended tool.
:::
## Parcel
Parcel should play nice with SheetJS out of the box.
:::warning Parcel Bug
Errors of the form `Could not statically evaluate fs call` stem from a Parcel
bug. Upgrade to Parcel version 1.5.0 or later.
:::
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against parcel `2.8.3`
:::
This demo follows the [Presidents Example](/docs/getting-started/example).
1) Save the following to `index.html`:
```html title="index.html"
SheetJS export demo
```
2) Install the SheetJS node module:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
3) Run the Parcel CLI tool:
```bash
npx -y parcel@2.8.3 index.html
```
4) Access the page listed in the output (typically `http://localhost:1234`) and
click the "Click to Export!" button to generate a file.
## RequireJS
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/requirejs)**
## Rollup
Rollup requires `@rollup/plugin-node-resolve` to support NodeJS modules:
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against Rollup 3.21.5
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} rollup@3.21.5 @rollup/plugin-node-resolve
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} rollup@3.21.5 @rollup/plugin-node-resolve
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} rollup@3.21.5 @rollup/plugin-node-resolve
2) Save the following to `index.js`:
```js title="index.js"
// highlight-next-line
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) Bundle the script:
```bash
npx rollup index.js --plugin @rollup/plugin-node-resolve --file bundle.js --format iife
```
4) Create a small HTML page that loads the script. Save to `index.html`:
```html title="index.html"
SheetJS Presidents Demo
```
5) 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.
## Snowpack
Snowpack works with no caveats.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against Snowpack `3.8.8`
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2) Save the following to `index.js`:
```js title="index.js"
// highlight-next-line
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 a small HTML page that loads the script. Save to `index.html`:
```html title="index.html"
SheetJS Presidents Demo
```
:::note pass
Unlike other bundlers, Snowpack requires a full page including `HEAD` element.
:::
4) Build for production:
```bash
npx snowpack@3.8.8 build
```
5) Start a local HTTP server, then go to `http://localhost:8080/`
```bash
npx http-server build/
```
Click on "Click here to export" to generate a file.
## 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.
:::
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against SWC 1.2.246
:::
1) Install the dependencies using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} regenerator-runtime @swc/cli @swc/core@1.2.246
:::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"
SheetJS Presidents Demo
```
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.
#### SystemJS
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/systemjs)**
## Vite
ViteJS is compatible with SheetJS versions starting from 0.18.10.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against ViteJS `4.3.5`
:::
1) Create a new ViteJS project:
```bash
npm create vite@latest sheetjs-vite -- --template vue-ts
cd sheetjs-vite
npm i
```
2) Add the SheetJS dependency:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
3) Replace `src\components\HelloWorld.vue` with:
```html title="src\components\HelloWorld.vue"
```
4) Run `npm run dev` and test functionality by opening a web browser to
`http://localhost:5173/` and clicking the button
5) Run `npx vite build` and verify the generated pages work by running a local
web server in the `dist` folder:
```bash
npx http-server dist/
```
Access `http://localhost:8080` in your web browser and click the export button.
:::note pass
The [Vite section of the Content demo](/docs/demos/static/vitejs) covers asset
loaders. They are ideal for static sites pulling data from sheets at build time.
:::
#### Webpack
**[The exposition has been moved to a separate page.](/docs/demos/frontend/bundler/webpack)**
## WMR
WMR works with no caveats.
Complete Example (click to show)
:::note
This demo was last tested on 2023 May 07 against WMR `3.8.0`
:::
1) Install the tarball using a package manager:
{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
{`\
yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
2) Save the following to `index.js`:
```js title="index.js"
// highlight-next-line
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 a small HTML page that loads the script. Save to `index.html`:
```html title="index.html"
SheetJS Presidents Demo
```
4) Build for production:
```bash
npx wmr@3.8.0 build
```
5) Start a local HTTP server in `dist` folder and go to `http://localhost:8080/`
```bash
npx http-server dist/
```
Click on "Click here to export" to generate a file.