Problem
The endpoint bundle pulls in node:fs, which workerd only provides under the
nodejs_compat compatibility flag. On a stock @astrojs/cloudflare site the
module fails to resolve and the whole site 500s — not just /api/ask, since the
dev server can't build the route:
[vite]: Rolldown failed to resolve import "node:fs"
(resolved id: node:fs) in @hevmind/ask/src/digest/tree.ts.
astro build warns about the same thing more quietly:
[WARN] [vite] Unexpected Node.js imports for environment "prerender".
Do you need to enable the "nodejs_compat" compatibility flag?
Cause
endpoint.ts:12
statically imports from the digest tree module:
import { digestTreeFiles } from './digest/tree.ts';
and tree.ts:1
imports fs at module top level:
import { readFileSync, readdirSync, statSync } from 'node:fs';
import path from 'node:path';
Why this one is easy
digestTreeFiles doesn't use fs at all. It's pure — it takes an in-memory
Digest and renders it to DigestTreeFile[]
(tree.ts:74),
and the endpoint hands it the digest it already got from the
virtual:hev-ask/digest module, not from disk
(endpoint.ts:201).
Every actual fs caller in that file is build-time or CLI only:
| Function |
Uses fs |
Called from |
digestTreeFiles |
no |
the endpoint (worker) |
renderMetaFile, renderNodeFile, nodePath, … |
no |
digestTreeFiles |
readDigestArtifact |
statSync |
integration.ts (Node) |
readDigestTree |
readFileSync |
Node |
readLegacyJson |
readFileSync |
Node |
walk |
readdirSync |
Node |
So the worker is paying for a Node dependency it never calls. It's purely an
import-graph artifact.
Fix
Split the module along the line that already exists:
digest/tree-render.ts — the pure serializers (digestTreeFiles and the
render* / *Path helpers). No node:fs, no node:path.
digest/tree.ts — keeps the fs readers, imports the pure module.
The endpoint then imports only tree-render.ts and the worker bundle has no
Node builtins from this path. No behavior change, no nodejs_compat needed, and
it keeps ask digest bundle / the tarball route working as-is.
node:path usage in the pure helpers (if any survive the split) should become
plain string joins — it's all POSIX-style digest-relative paths.
Note
Telling users to enable nodejs_compat would also make the error go away, but
it's the wrong fix: it papers over a Node dependency in worker code that isn't
needed, and it's an extra config step on the path we advertise as turnkey.
Found while wiring 0.3.4 into a Starlight docs site. Present on main
(a3204b4), not just the 0.3.4 tag. Fixing this alone is not sufficient to get
the Cloudflare path working — #3 is waiting immediately
behind it.
Problem
The endpoint bundle pulls in
node:fs, which workerd only provides under thenodejs_compatcompatibility flag. On a stock@astrojs/cloudflaresite themodule fails to resolve and the whole site 500s — not just
/api/ask, since thedev server can't build the route:
astro buildwarns about the same thing more quietly:Cause
endpoint.ts:12statically imports from the digest tree module:
and
tree.ts:1imports fs at module top level:
Why this one is easy
digestTreeFilesdoesn't use fs at all. It's pure — it takes an in-memoryDigestand renders it toDigestTreeFile[](tree.ts:74),
and the endpoint hands it the digest it already got from the
virtual:hev-ask/digestmodule, not from disk(endpoint.ts:201).
Every actual fs caller in that file is build-time or CLI only:
digestTreeFilesrenderMetaFile,renderNodeFile,nodePath, …digestTreeFilesreadDigestArtifactstatSyncintegration.ts(Node)readDigestTreereadFileSyncreadLegacyJsonreadFileSyncwalkreaddirSyncSo the worker is paying for a Node dependency it never calls. It's purely an
import-graph artifact.
Fix
Split the module along the line that already exists:
digest/tree-render.ts— the pure serializers (digestTreeFilesand therender*/*Pathhelpers). Nonode:fs, nonode:path.digest/tree.ts— keeps the fs readers, imports the pure module.The endpoint then imports only
tree-render.tsand the worker bundle has noNode builtins from this path. No behavior change, no
nodejs_compatneeded, andit keeps
ask digest bundle/ the tarball route working as-is.node:pathusage in the pure helpers (if any survive the split) should becomeplain string joins — it's all POSIX-style digest-relative paths.
Note
Telling users to enable
nodejs_compatwould also make the error go away, butit's the wrong fix: it papers over a Node dependency in worker code that isn't
needed, and it's an extra config step on the path we advertise as turnkey.
Found while wiring 0.3.4 into a Starlight docs site. Present on
main(a3204b4), not just the 0.3.4 tag. Fixing this alone is not sufficient to get
the Cloudflare path working — #3 is waiting immediately
behind it.