diff --git a/docz/docs/04-getting-started/03-demos/09-bundler.md b/docz/docs/04-getting-started/03-demos/09-bundler.md
new file mode 100644
index 0000000..973ae2d
--- /dev/null
+++ b/docz/docs/04-getting-started/03-demos/09-bundler.md
@@ -0,0 +1,103 @@
+---
+sidebar_position: 9
+title: Bundlers
+---
+
+import current from '/version.js';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+SheetJS predates ECMAScript modules and bundler tools like Webpack. As best
+practices have evolved, stress testing SheetJS libraries have revealed bugs in
+the respective bundlers.  This demo collects various notes and provides basic
+examples. Issues should be reported to the respective bundler projects.
+
+## Parcel
+
+Parcel Bundler should play nice with SheetJS out of the box.
+
+Errors of the form `Could not statically evaluate fs call` stem from a 
+[parcel bug](https://github.com/parcel-bundler/parcel/pull/523). Upgrade to
+Parcel version 1.5.0 or later.
+
+<details><summary><b>Complete Example</b> (click to show)</summary>
+
+This demo follows the [Presidents Example](../../example).
+
+1) Save the following to `index.html`:
+
+```html title="index.html"
+<body>
+<h3>SheetJS <span id="vers"></span> export demo</h3>
+<button id="xport">Click to Export!</button>
+<!-- the script tag must be marked as `type="module"` -->
+<!-- highlight-next-line -->
+<script type="module">
+// ESM-style import from "xlsx"
+// highlight-next-line
+import { utils, version, writeFile } from 'xlsx';
+
+document.getElementById("vers").innerText = version;
+document.getElementById("xport").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 = 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");
+};
+</script>
+<body>
+```
+
+2) Install the SheetJS node module:
+
+<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>
+
+3) Run the Parcel CLI tool:
+
+```bash
+npx -y parcel 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.
+
+</details>
\ No newline at end of file
diff --git a/docz/docs/04-getting-started/03-demos/index.md b/docz/docs/04-getting-started/03-demos/index.md
index 1a86f40..bf4da23 100644
--- a/docz/docs/04-getting-started/03-demos/index.md
+++ b/docz/docs/04-getting-started/03-demos/index.md
@@ -50,7 +50,7 @@ The demo projects include small runnable examples and short explainers.
 ### Bundlers and Tooling
 
 - [`browserify`](https://github.com/SheetJS/SheetJS/tree/master/demos/browserify/)
-- [`parcel`](https://github.com/SheetJS/SheetJS/tree/master/demos/parcel/)
+- [`parcel`](./bundler#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/)
diff --git a/docz/docs/06-solutions/05-output.md b/docz/docs/06-solutions/05-output.md
index 53a9f90..dcb7d7c 100644
--- a/docz/docs/06-solutions/05-output.md
+++ b/docz/docs/06-solutions/05-output.md
@@ -90,6 +90,48 @@ XLSX.writeFile(workbook, "out.xlsb");
 /* at this point, out.xlsb will have been downloaded */
 ```
 
+:::caution Web Workers
+
+None of the file writing APIs work from Web Workers.  To generate a file:
+
+1) use `XLSX.write` with type `array` to generate a `Uint8Array`:
+
+```js
+// in the web worker, generate the XLSX file as a Uint8Array
+const u8 = XLSX.write(workbook, { type: "array", bookType: "xlsx" });
+```
+
+2) send the data back to the main thread:
+
+```js
+// in the web worker, send the generated data back to the main thread
+postMessage({t: "export", v: u8 });
+```
+
+3) from the main thread, add an event listener to write to file:
+
+```js
+// in the main page
+worker.addEventListener('message', function(e) {
+  if(e && e.data && e.data.t == "export") {
+    e.stopPropagation();
+    e.preventDefault();
+    // data will be the Uint8Array from the worker
+    const data = e.data.v;
+
+    var blob = new Blob([data], {type:"application/octet-stream"});
+    var url = URL.createObjectURL(blob);
+    var a = document.createElement("a");
+    a.download = "SheetJSXPort.xlsx";
+    a.href = url;
+    document.body.appendChild(a);
+    a.click();
+  }
+});
+```
+
+:::
+
 <details>
   <summary><b>SWF workaround for Windows 95+</b> (click to show)</summary>
 
diff --git a/docz/package.json b/docz/package.json
index 0727b8c..7d3b8da 100644
--- a/docz/package.json
+++ b/docz/package.json
@@ -17,13 +17,13 @@
     "@cmfcmf/docusaurus-search-local": "^0.10.0",
     "@docusaurus/core": "2.0.0-beta.20",
     "@docusaurus/preset-classic": "2.0.0-beta.20",
-    "@docusaurus/theme-common": "^2.0.0-beta.20",
-    "@docusaurus/theme-live-codeblock": "^2.0.0-beta.20",
-    "@mdx-js/react": "^1.6.22",
-    "clsx": "^1.1.1",
-    "prism-react-renderer": "^1.3.1",
-    "react": "^17.0.2",
-    "react-dom": "^17.0.2",
+    "@docusaurus/theme-common": "2.0.0-beta.20",
+    "@docusaurus/theme-live-codeblock": "2.0.0-beta.20",
+    "@mdx-js/react": "1.6.22",
+    "clsx": "1.1.1",
+    "prism-react-renderer": "1.3.1",
+    "react": "17.0.2",
+    "react-dom": "17.0.2",
     "xlsx": "https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz"
   },
   "devDependencies": {