Summary
The docs (Querying Content → "Static vs. Server Rendering", and coming-from/astro) advertise static prerendering via getStaticPaths() + getEmDashCollection()/getEmDashEntry(). In practice this fails at build time. getEmDashCollection() returns { entries: [], error } where the error message is Failed to load collection: __filename is not defined (and a cascade of follow-on errors once that's addressed). Calling the underlying loader directly (emdashLoader().loadCollection(...) from emdash/runtime) works fine in the same build — so the failure is specific to the path through Astro's Live Content Collections (getLiveCollection from astro:content), which is what getEmDashCollection is built on.
Environment
- emdash 0.17.x (
emdash, @emdash-cms/cloudflare, @emdash-cms/auth-atproto)
- astro 6.4.x,
@astrojs/node adapter (standalone), output: "server" with public pages marked export const prerender = true (hybrid prerender)
- database:
sqlite({ url: "file:..." }) pointing at a populated local DB
- pnpm (strict, non-hoisted node_modules)
Root cause (what we traced)
getEmDashCollection → getLiveCollection("_emdash", …) → the live loader registered in src/live.config.ts. Astro's live-content-collections build pipeline bundles emdash's loader (emdash is in the integration's ssr.noExternal), but that bundling does NOT honor the integration's ssr.external (NODE_NATIVE_EXTERNALS = ["better-sqlite3","bindings","file-uri-to-path","@libsql/kysely-libsql","pg"]). So the native better-sqlite3/bindings chain gets inlined into the prerender bundle and breaks. The error cascade when you peel it back:
__filename is not defined (CJS global absent in the ESM prerender bundle — bindings uses it)
- with a
__filename/__dirname → import.meta shim: Could not dynamically require ".../better_sqlite3.node" (Rollup/@rollup/plugin-commonjs cannot inline a native .node addon)
- externalizing
better-sqlite3 in build.rollupOptions.external: Cannot find package 'better-sqlite3' imported from dist/server/.prerender/chunks/… (it's a transitive dep of emdash, so it isn't resolvable from the project root under pnpm's strict layout)
Notably the SSR server bundle DOES externalize better-sqlite3 correctly (import BetterSqlite3 from 'better-sqlite3'); only the .prerender chunk path mishandles it.
Workaround that makes static prerender succeed
In the consuming app's astro.config.mjs (node-adapter static target only):
build.rollupOptions.external: ["better-sqlite3","bindings","file-uri-to-path"]
define: { __filename: "import.meta.filename", __dirname: "import.meta.dirname" }
- add
better-sqlite3 as a DIRECT dependency (so it resolves when externalized under pnpm)
With those three, getEmDashCollection returns populated entries at build time and all locales prerender to static HTML correctly.
Ask
Either (a) have the live-collections build path honor the integration's ssr.external (so the native driver stays external in the .prerender bundle), or (b) document the required rollupOptions.external + direct-dependency steps in the "Static vs. Server Rendering" guide. Today the documented static path doesn't work out of the box with the sqlite driver.
Summary
The docs (Querying Content → "Static vs. Server Rendering", and coming-from/astro) advertise static prerendering via
getStaticPaths()+getEmDashCollection()/getEmDashEntry(). In practice this fails at build time.getEmDashCollection()returns{ entries: [], error }where the error message isFailed to load collection: __filename is not defined(and a cascade of follow-on errors once that's addressed). Calling the underlying loader directly (emdashLoader().loadCollection(...)fromemdash/runtime) works fine in the same build — so the failure is specific to the path through Astro's Live Content Collections (getLiveCollectionfromastro:content), which is whatgetEmDashCollectionis built on.Environment
emdash,@emdash-cms/cloudflare,@emdash-cms/auth-atproto)@astrojs/nodeadapter (standalone),output: "server"with public pages markedexport const prerender = true(hybrid prerender)sqlite({ url: "file:..." })pointing at a populated local DBRoot cause (what we traced)
getEmDashCollection→getLiveCollection("_emdash", …)→ the live loader registered insrc/live.config.ts. Astro's live-content-collections build pipeline bundles emdash's loader (emdash is in the integration'sssr.noExternal), but that bundling does NOT honor the integration'sssr.external(NODE_NATIVE_EXTERNALS = ["better-sqlite3","bindings","file-uri-to-path","@libsql/kysely-libsql","pg"]). So the nativebetter-sqlite3/bindingschain gets inlined into the prerender bundle and breaks. The error cascade when you peel it back:__filename is not defined(CJS global absent in the ESM prerender bundle —bindingsuses it)__filename/__dirname→import.metashim:Could not dynamically require ".../better_sqlite3.node"(Rollup/@rollup/plugin-commonjs cannot inline a native.nodeaddon)better-sqlite3inbuild.rollupOptions.external:Cannot find package 'better-sqlite3' imported from dist/server/.prerender/chunks/…(it's a transitive dep of emdash, so it isn't resolvable from the project root under pnpm's strict layout)Notably the SSR server bundle DOES externalize better-sqlite3 correctly (
import BetterSqlite3 from 'better-sqlite3'); only the.prerenderchunk path mishandles it.Workaround that makes static prerender succeed
In the consuming app's
astro.config.mjs(node-adapter static target only):build.rollupOptions.external: ["better-sqlite3","bindings","file-uri-to-path"]define: { __filename: "import.meta.filename", __dirname: "import.meta.dirname" }better-sqlite3as a DIRECT dependency (so it resolves when externalized under pnpm)With those three,
getEmDashCollectionreturns populated entries at build time and all locales prerender to static HTML correctly.Ask
Either (a) have the live-collections build path honor the integration's
ssr.external(so the native driver stays external in the.prerenderbundle), or (b) document the requiredrollupOptions.external+ direct-dependency steps in the "Static vs. Server Rendering" guide. Today the documented static path doesn't work out of the box with the sqlite driver.