Bundling Sheets with Webpack
Webpack is a module bundler.
SheetJS is a JavaScript library for reading and writing data from spreadsheets.
This demo uses Webpack and SheetJS to export data. We'll explore how to bundle SheetJS in a site using Webpack and how to export data to spreadsheets.
The Webpack section of the Content demo covers asset loaders. They are ideal for static sites pulling data from sheets at build time.
This demo focuses on integration details with the Webpack bundler.
The demos follow the "Export Tutorial", which covers SheetJS library usage in more detail.
This demo was tested in the following environments:
Version | Date | Required Workarounds |
---|---|---|
2.7.0 | 2024-03-16 | Import xlsx/dist/xlsx.full.min.js |
3.12.0 | 2024-03-16 | Import xlsx/dist/xlsx.full.min.js |
4.47.0 | 2024-03-16 | Downgrade NodeJS (tested v16.20.2) |
5.90.3 | 2024-03-16 |
Integration Details​
The "Frameworks" section covers installation with Yarn and other package managers.
After installing the SheetJS module in a Webpack 5 project, import
statements
and require
expressions can load relevant parts of the library.
The ECMAScript Module build has no require
or import
statements and does
not use process
or any variable that Webpack could interpret as a NodeJS
feature. Various package.json
fields have been added to appease various
Webpack versions starting from the 2.x
series.
Projects that import data will use methods such as read
1 to parse workbooks
and sheet_to_json
2 to generate usable data from files. As sheet_to_json
is part of the utils
object, the required import is:
import { read, utils } from 'xlsx';
Projects that export data will use methods such as json_to_sheet
3 to
generate worksheets and writeFile
4 to export files. As json_to_sheet
is
part of the utils
object, the required import is:
import { utils, writeFile } from 'xlsx';
The writeFileXLSX
function is a small version of writeFile
that exclusively
supports generating XLSX spreadsheets. When the application only allows XLSX
exports, writeFileXLSX
will reduce the final page size.
CommonJS and ESM​
Webpack bundled the CommonJS build in older versions of the library. Version
0.18.1
changed the NodeJS module package so that Webpack uses the ESM build.
The CommonJS build includes the codepage support library for XLS processing.
The ESM build does not include the codepage support library. As described in the installation instructions, the codepage dependency should be imported explicitly:
import * as XLSX from 'xlsx';
import * as cptable from 'xlsx/dist/cpexcel.full.mjs';
set_cptable(cptable);
Legacy Webpack​
Some older webpack projects will throw an error in the browser:
require is not defined (xlsx.mjs)
This was a bug in Webpack and affected projects built with create-react-app
.
If upgrading Webpack is not feasible, explicitly import the standalone script:
import * as XLSX from 'xlsx/dist/xlsx.full.min.js';
Complete Example​
- Initialize a new project:
mkdir sheetjs-webpack
cd sheetjs-webpack
npm init -y
- Install the tarball using a package manager:
- npm
- pnpm
- Yarn
npm i --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
pnpm install --save https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
yarn add https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz
- Save the following to
index.js
:
import { utils, version, writeFileXLSX } from 'xlsx';
document.getElementById("xport").addEventListener("click", function() {
/* fetch JSON data and parse */
var url = "https://docs.sheetjs.com/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");
});
});
The minifier that ships with Webpack 2.x does not handle async
functions or
ES6 arrow functions.
To demonstrate compatibility with older versions of Webpack, the index.js
script uses normal functions and traditional Promise chains.
- Create a small
webpack.config.js
script that writes toindex.min.js
:
module.exports = {
/* entry point index.js */
entry: './index.js',
/* write to index.min.js */
output: { path:__dirname, filename: './index.min.js' }
}
- Build for production. The command depends on the version of webpack:
- 2.x and 3.x
- 4.x, 5.x and beyond
In Webpack 2.x and 3.x, the import statement must use the standalone script.
Replace the import statement in index.js
with the following:
import { utils, version, writeFileXLSX } from 'xlsx/dist/xlsx.full.min.js';
This line must be changed before bundling.
Webpack 2.x
npx webpack@2.x -p
Webpack 3.x
npx webpack@3.x -p
The webpack tooling is not designed for switching between versions. A specific version above 4.0 can be pinned by locally installing webpack and the CLI tool.
Webpack 4.x
Webpack 4 is incompatible with Node 18+. It will elicit the following error:
Error: error:0308010C:digital envelope routines::unsupported
When this demo was last tested, NodeJS was locally downgraded to 16.20.2
npm i --save webpack@4.x webpack-cli@4.x
npx webpack --mode=production
Webpack 5.x
npm i --save webpack@5.x webpack-cli@5.x
npx webpack --mode=production
Webpack latest
npm i --save webpack webpack-cli
npx webpack --mode=production
- Create a small HTML page that loads the script. Save to
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>
- Start a local HTTP server:
npx http-server .
- Load the displayed URL (typically
http://localhost:8080/
) in a web browser.
Click on "Click here to export" to generate a file.