
Author PDFs as Vue components in Nuxt - render them in the browser or on a server route, zero config.
The Nuxt module for @jasy/vue and @jasy/pdf.
Add it to modules and the components and render helpers are just there - no imports, no wiring. Render a
PDF client-side with usePdf, or stream one from a Nitro route with definePdfHandler. No headless
browser, no Java.
npx nuxi module add @jasy/nuxt
That installs the package and adds it to modules for you. Or wire it up by hand:
pnpm add @jasy/nuxt
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["@jasy/nuxt"],
});
usePdfAuthor a PDF as a Vue component - the jasy components are auto-registered, so no imports:
<!-- Invoice.vue -->
<template>
<Document :size="11">
<Page :size="'A4'" :margin="48">
<Text :size="24" bold color="#0a2348">Invoice #{{ id }}</Text>
</Page>
</Document>
</template>
<script setup lang="ts">
import Invoice from "./Invoice.vue";
const { open, download, pending } = usePdf(Invoice, { props: { id: 42 } });
</script>
<template>
<button :disabled="pending" @click="open">View PDF</button>
</template>
open() and download() render on demand and reuse the result, so one click is one render. Pass
{ immediate: true } to pre-render on mount.
definePdfHandlerThe @jasy/pdf tree API is auto-imported in server/. No Vue, no browser - build the document and stream
it:
// server/api/invoice/[id].get.ts
export default definePdfHandler((event) =>
Document([
Page({ size: "A4", margin: 48 }, [
Text(`Invoice #${getRouterParam(event, "id")}`, { size: 24, bold: true }),
]),
]),
);
GET /api/invoice/42 streams application/pdf. Need auth or a data fetch first? Use
sendPdf(event, doc, opts) inside your own handler, or renderToBytes(doc) to just get the bytes (save
them, attach to an email, anything).
Wrap a route in Nitro's cache - keyed by path + query, so it caches per request out of the box:
export default definePdfHandler(build, { cache: { maxAge: 3600 } });
Expired entries re-render fresh (swr is off by default) - a stale invoice is never served.
usePdf and definePdfHandler / sendPdf forward @jasy/pdf render options via renderOptions - so
AES-256 password protection is one option away, client or server:
// client
const { download } = usePdf(Invoice, { renderOptions: { encrypt: { userPassword: "secret" } } });
// server
export default definePdfHandler(build, { renderOptions: { encrypt: { userPassword: "secret" } } });
ownerPassword + permissions are optional. (AES-256 ≠ PDF/A, so this is not for ZUGFeRD invoices.)
Document · Page · Column · Row · Box · Padding · Text ·
Image · Table and the rest. Set a prefix to dodge name clashes (prefix: "Pdf" makes it
<PdfDocument>).usePdf and renderToPdf on the client; the @jasy/pdf tree API, definePdfHandler
and sendPdf on the server.export default defineNuxtConfig({
modules: ["@jasy/nuxt"],
jasy: {
autoImport: true, // auto-register components + the tree API (default true)
prefix: "Pdf", // <PdfDocument> in templates, PdfDocument(...) in server/ (default none)
},
});
@jasy/pdf - the pure-TypeScript PDF engine@jasy/vue - author PDFs as Vue componentsMIT, by Florian Heuberger