Branch: modernize/esm-build-v2 · Commit: 5c1f273
This document explains what broke, why, and exactly what changed to fix
it. The goal of v2 was to make @linways/table-to-excel load in a modern
bundler (Vite / Rollup / esbuild) without any consumer-side workaround.
Importing the library inside a Vite-built app threw at module load time — before any table was ever exported:
TypeError: Cannot read properties of undefined (reading 'TYPED_ARRAY_SUPPORT')
v1.0.4 shipped dist/tableToExcel.js as a Parcel v1 UMD bundle. Two facts
about that bundle combined to crash in the browser:
-
Parcel passes a hidden 4th argument to every module factory. Parcel's runtime invokes each wrapped module like this:
moduleFn.call(exports, require, module, exports, this) // ^^^^ → readable as arguments[3]
In Node, top-level
thisis the Nodeglobalobject, soarguments[3]hands each module a reference toglobal. -
The inlined
buffer@4.xpolyfill relies on that back door. It does:var t = arguments[3]; // expects Node global ... t.TYPED_ARRAY_SUPPORT ... // reads a property off it
When the same bundle is served by Vite as a native ES module, it runs in
strict mode, where top-level this is undefined. Parcel therefore
forwards undefined as the 4th argument, arguments[3] is undefined, and
undefined.TYPED_ARRAY_SUPPORT throws the instant the module is imported.
Where the old buffer@4 polyfill came from: v1 imported ExcelJS through a
deep dist path —
../node_modules/exceljs/dist/es5/exceljs.browser — which is exceljs 1.x's
pre-bundled ES5 build that inlines buffer@4. That is the exact code Parcel
wrapped and shipped.
The FAPI app previously carried a Vite build-time plugin
(vite-plugins/fix-table-to-excel-globals.ts) that regex-rewrote every
arguments[3] in the bundle to (arguments[3] || globalThis), in two
plugin shapes (esbuild for the dev prebundle, Vite transform for the Rollup
production build). v2 makes that plugin unnecessary.
-import ExcelJS from "../node_modules/exceljs/dist/es5/exceljs.browser";
+import ExcelJS from "exceljs";Removes the deep dist path that pulled in the buffer@4 polyfill. The bundler
now resolves exceljs normally and picks its modern browser build.
package.json dependency bumped ^1.10.0 → ^4.4.0. ExcelJS 4 uses native
Uint8Array and does not ship the crashing buffer@4 read-of-global
form. ExcelJS is kept external (not inlined) so consumers bundle a single
clean copy of exceljs@4.
- "build": "parcel build src/tableToExcel.js"
+ "build": "tsup src/tableToExcel.js --format esm,cjs --clean --sourcemap"tsup emits standard, spec-compliant ESM and CJS with no Parcel runtime
wrapper and no hidden arguments[3] convention — so the whole bug class is
gone at the source, not patched over.
| Field | v1.0.4 | v2.0.0 |
|---|---|---|
version |
1.0.4 |
2.0.0 |
type |
(none, CJS) | module |
main |
./dist/tableToExcel.js |
./dist/tableToExcel.cjs |
module |
— | ./dist/tableToExcel.js |
browser |
— | ./dist/tableToExcel.js |
exports |
— | import→.js, require→.cjs, default→.js |
sideEffects |
— | ["./dist/tableToExcel.js", "./dist/tableToExcel.cjs"] |
sideEffects lists the dist files because the module has a real side effect —
it assigns window.TableToExcel = TableToExcel — so tree-shakers must not drop
it.
- "test": "mocha -r @babel/register -r @babel/polyfill -r jsdom-global/register"
+ "test": "vitest run"New vitest.config.ts runs the existing test/parser.test.js (29 chai
assertions) under jsdom. All 29 pass against exceljs 4.4 — confirming the
DOM-parsing / styling API surface is unchanged.
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: { environment: 'jsdom', globals: true, include: ['test/**/*.test.js'] },
})Removed devDeps: @babel/*, parcel-bundler, mocha, jsdom-global, plus the
babel config block. Added: tsup, vitest, typescript (tsup needs it
present even for a JS entry), jsdom@25.
Removed stale Parcel artifacts (index.html, index.js,
tableToExcel.517b1af9.js, .map files). New outputs:
dist/tableToExcel.js(ESM) +.js.mapdist/tableToExcel.cjs(CJS) +.cjs.map
| Layer | Check | Result |
|---|---|---|
| 1. Build static analysis | grep 'arguments\[3\]' and grep 'TYPED_ARRAY_SUPPORT' in new dist |
0 hits |
| 2. Unit tests | 29 parser tests under Vitest/jsdom on exceljs 4.4 | Pass |
| 3. Consumer build | FAPI pnpm build with the workaround plugin removed |
Pass |
The v1 crash was a read of a property off undefined (arguments[3].X); a
grep of the v2 dist confirms zero such reads remain — the bug is structurally
absent, not merely masked.
- Point the dependency at v2 (git branch or, once published,
^2.0.0). - Delete any
arguments[3]/TYPED_ARRAY_SUPPORTVite/esbuild workaround plugin and its registrations. - Clear the bundler cache (
rm -rf node_modules/.vite) and re-export a sheet.
The runtime API is unchanged — TableToExcel.convert(table, opts) and the
data-* cell attributes work exactly as before.
- Ship
.d.tstypes so consumers can drop their local module shim. - Add a UMD build if any
<script>-tag consumers still need one.