Skip to content
Inkoxide

Search covers every page and heading of the docs. Use ↑ ↓ and ↵.

In the browser

Edit this page

The same templates render in a browser, with the engine as WebAssembly in a Web Worker, so the page keeps responding while it renders. Install the module next to the package, and import from @inkoxide/render/browser:

npm install @inkoxide/render @inkoxide/wasm
import { PdfDownloadLink, PdfViewer, usePdf } from '@inkoxide/render/browser';

function InvoicePage({ invoice }: { invoice: InvoiceData }) {
  const doc = <Invoice invoice={invoice} />;
  return (
    <>
      <PdfDownloadLink document={doc} fileName="invoice.pdf">
        {({ loading }) => (loading ? 'Rendering…' : 'Download')}
      </PdfDownloadLink>
      <PdfViewer document={doc} style={{ width: '100%', height: 800 }} />
    </>
  );
}
  • usePdf(element, options?) renders when the component mounts and returns { blob, url, loading, error, update }; update(element?) renders again. A render that starts stops the one still running, and the object URL is revoked when a new one replaces it.
  • <PdfDownloadLink> is a link that downloads the PDF, and <PdfViewer> an <iframe> with the browser's own viewer. Each renders when it mounts: give it another key to render again.
  • renderToBuffer and renderToBlob render outside React components, and generate renders a template. A signal in their options, or timeoutMs (a time in ms), stops a render: its worker ends, and the next render starts a new one. A render that times out rejects with a DOMException named TimeoutError.
  • init(options?) starts the engine, and every render calls it; only the options of the first call count. wasm is where the module comes from (a URL, a Response, its bytes or a compiled WebAssembly.Module); assets is a folder to serve the bundled fonts and hyphenation patterns from: fonts/ and hyphenation/ from @inkoxide/render's assets/, with the .bin files of @inkoxide/wasm's hyphenation/ in hyphenation/ too; worker: false renders on the calling thread.
  • clearCaches() empties the engine's caches of decoded images, font subsets and SVG text. The memory stays with the engine, which reuses it for the next renders; the PDFs are the same.

Setting up. Bundlers copy the module, the worker and the bundled fonts, which the packages refer to with new URL(…, import.meta.url). With Vite, set worker: { format: 'es' }, and leave @inkoxide/render and @inkoxide/wasm out of optimizeDeps, so that those URLs stay next to their files. examples/browser is a page set up that way.

Fonts and images. A bundled font is downloaded the first time a document uses it, as a TrueType file, for the same PDF as on the server. Font.register takes a URL (relative to the page) or the bytes; a file path (a file: URL, a drive letter or a backslash) fails the render with INVALID_FONT. A WOFF2 font gives other PDF bytes than its TrueType file; WOFF gives the same. Images come as bytes in images, or from the hosts allowed in remoteImages: the requests carry no cookies, need CORS, and a redirect is refused. localImages is not available.

Content Security Policy. The engine needs script-src 'wasm-unsafe-eval' and a worker of the page's origin (worker-src 'self'). Nothing needs 'unsafe-eval', and the page needs no cross-origin isolation (COOP and COEP).

What differs from Node.

  • Renders run in one worker, one at a time, on one thread: threads may only be 1.
  • renderToFile, renderToStream and image files are not available.
  • The engine module is about 1.2 MB to download with brotli, once. A bundled font (65 to 245 KB with brotli) is downloaded when a document first draws with it: Noto Sans, the fallback, only for a character Inter lacks. A language's hyphenation patterns (1 to 350 KB) are downloaded when a document first hyphenates text in it.
  • The PDF has the bytes Node renders, except where SVG markers are rotated: their numbers can differ in the last digits, since the browser's math library rounds differently.
  • A bug in the engine fails the render with INTERNAL; the next render runs in a new instance.

Synced from packages/render/GUIDE.md in the inkoxide repository.