Today I want to share a problem I encountered when integrating SheetJS with Nuxt specifically in cases without authentication, accessing the path directly works fine. But when the path requires Server-Side Authentication, it throws the error below.
Cannot find module '/app/node_modules/xlsx/dist/cpexcel.js' from '/app/server/chunks/build/index-64cha0zE.mjs'
Why
- SheetJS was designed to separate the codepage table into an optional file in order to reduce bundle size.SheetJS was designed to separate the codepage table into an optional file in order to reduce bundle size.
- The legacy version (0.18.x) still relies on a CJS build that loads cpexcel via a dynamic
require()wrapped in atry/catchblock. As a result, when Nitro bundles the server output using Rollup and node-file-trace, Rollup treats the dynamic require() inside the try/catch as optional code and skips it. so cpexcel.js never gets copied into.output. At runtime, the path resolution is correct, but the file is simply not there because it was never included during the build.
Solution
Upgrading the SheetJS library from 0.18.5 → 0.20.3 has two approaches, but for versions after 18, SheetJS requires you to pull the package directly from https://cdn.sheetjs.com/ instead.
- First Solution (Public to Private Repo)
- Public to Private Repo such as Nexus. You can follow the instruction to push Sheetjs tarball on this blog
- Second Solution (Add tarball in Code Repository)
- First, define the repository structure to determine where to place the tarball — in this case, SheetJS will be stored inside a
vendorfolder.
simple-redmine-client/ ├── vendor/ │ └── xlsx-0.20.3.tgz ├── package.json ├── bun.lock ├── nuxt.config.ts └── Dockerfile


- Remove old xlsx package
bun remove xlsx
- Install Package from Vendor Folder
# Download curl -L -o vendor/xlsx-0.20.3.tgz https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz # Install bun add ./vendor/xlsx-0.20.3.tgz
Note: If you do not run bun remove first, it will cause a dependency exception when installing the package.
Next, update the code — if the existing code still uses require, refactor it to use a namespace import instead.
- Old Code
import XLSX from 'xlsx'
const XLSX = require('xlsx')
const wb = XLSX.readFile('data.xlsx')
---
import XLSX from 'xlsx' // <-- default import
const wb = XLSX.read(buf, { type: 'buffer' })
- Improve Code
import * as XLSX from 'xlsx' // 0.20.3 namespace import auto resolve ESM
If you have legacy codepages and need to read Windows-874 (TIS-620) files, you'll need to include
cpexcelas well — just follow the steps in the code below.
import * as XLSX from 'xlsx'
import * as cptable from 'xlsx/dist/cpexcel.full.mjs'
XLSX.set_cptable(cptable)
// ไฟล์ CSV ที่ export จากระบบเก่า/Excel บน Windows ไทย → มักเป็น CP874 ไม่มี BOM
const wb = XLSX.read(buf, { type: 'buffer', codepage: 874 })
- Test with
bun run buildand Then run manual test to export the Excel file and verify the output.
bun run build
For those using Container, you'll also need to COPY the tarball into the image during the build stage. You can spot the addition lines by looking at the highlighted sections.
# use the official Bun image # see all versions at https://hub.docker.com/r/oven/bun/tags FROM oven/bun:1.3 AS base WORKDIR /app # install dependencies into temp directory # this will cache them and speed up future builds FROM base AS install COPY package.json bun.lock ./ COPY vendor ./vendor COPY . . ENV npm_config_optional=true ENV npm_config_platform=linux ENV npm_config_arch=x64 RUN BUN_POSTINSTALL=enable bun install --frozen-lockfile # Copy project files into the image # [Optional] tests & build # Test stage FROM install AS test ENV NODE_ENV=test # Run tests and generate a report RUN bun test --reporter=junit --reporter-outfile=test-results.xml # Build stage FROM install AS build ENV NODE_ENV=production RUN bun run build # Copy production dependencies and source code into final image FROM oven/bun:1.3-alpine AS runtime WORKDIR /app # Copy necessary files from the 'install' stage to the 'runtime' stage # COPY --from=install /app/node_modules ./node_modules COPY --from=build --chown=bun:bun /app/.output . # Set user and expose port USER bun EXPOSE 3000/tcp # Run the app ENTRYPOINT [ "sh", "-c", "bun run /app/server/index.mjs" ]
Reference
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.



