Next.js and SSR
Extraction belongs on the server, the viewer belongs in the browser, and the line between them is the thing to get right.
Which half runs where
The universal half — parsing, extraction, chunking — runs in a route handler, a server action or a build script without any special handling. The viewer needs a DOM and therefore a client component; there is no server rendering of a paginated document, because pagination is measured from what the browser actually laid out.
import { extract } from '@genomdev/genom';
export async function POST(request: Request) {
const bytes = new Uint8Array(await request.arrayBuffer());
const doc = await extract(bytes);
return Response.json({ markdown: doc.toMarkdown() });
}Edge runtimes
The universal half has no Node built-ins in it: no fs, no path, no zlib, no Buffer. It runs on Vercel’s edge runtime, on Cloudflare Workers and in a service worker unchanged. @genomdev/genom/node is the one entry point that does not, and it says so in its name.
Keeping the client bundle small
Import the lazy descriptors, not the format packages, in anything a browser will download. A static import { docxView } from "@genomdev/docx/view" at the top of a client component puts the Word parser in the entry chunk; @genomdev/genom/lazy is descriptors and dynamic imports only, and it is twenty lines.
@genomdev/docx and the culprit is usually one import away.