A Nuxt 3 module for server-side PDF generation using Handlebars templates
npm install @maistik/nuxt-pdfA powerful Nuxt 3/4 module for server-side PDF generation using Handlebars templates. Generate beautiful, data-driven PDFs with support for multiple providers (Gotenberg, Browserless, Puppeteer Core) and built-in internationalization.
- 🎨 Handlebars Templates - Lightweight templating without Vue overhead
- 🌍 Internationalization - Built-in i18n support with {{t}} helper
- 🔄 Provider Agnostic - Support for Gotenberg, Browserless, and Puppeteer Core
- 🎯 SSR Safe - Everything runs server-side in Nitro/Node
- 🧩 Composable API - Easy-to-use usePdf() composable
- 📱 Responsive Design - CSS-based layouts with print media queries
- 🎪 Playground - Demo app with sample templates
``bash`
npm install @maistik/nuxt-pdf handlebars
Add the module to your nuxt.config.ts:
`typescript`
export default defineNuxtConfig({
modules: ['@maistik/nuxt-pdf'],
pdf: {
provider: 'puppeteer', // or 'gotenberg' or 'browserless'
components: ['pdf'],
sharedComponents: ['pdf/partials'],
enableI18n: true,
defaultLocale: 'en',
availableLocales: ['en', 'es', 'fr'],
i18nMessages: {
en: {
invoice: {
title: 'Invoice',
total: 'Total'
}
},
es: {
invoice: {
title: 'Factura',
total: 'Total'
}
}
},
providers: {
puppeteer: {
launchOptions: {
headless: true,
args: ['--no-sandbox']
}
}
}
}
})
Create pdf/Invoice.hbs in your project:
`handlebars
Invoice #{{invoiceNumber}}
| {{this.description}} | {{formatCurrency this.price}} |
$3
Use the composable in your Vue components:
`vue
`Providers
$3
Best for development and on-premise deployments:
`typescript
pdf: {
provider: 'puppeteer',
providers: {
puppeteer: {
launchOptions: {
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox']
}
}
}
}
`$3
Perfect for containerized environments:
`typescript
pdf: {
provider: 'gotenberg',
providers: {
gotenberg: {
url: 'http://gotenberg:3000'
}
}
}
`$3
Great for serverless deployments:
`typescript
pdf: {
provider: 'browserless',
providers: {
browserless: {
url: 'https://chrome.browserless.io',
apiKey: process.env.BROWSERLESS_API_KEY
}
}
}
`Built-in Helpers
$3
`handlebars
{{t "invoice.title"}}
`$3
`handlebars
{{formatCurrency 1234.56}}
{{formatCurrency 1234.56 "EUR"}}
`$3
`handlebars
{{formatDate date}}
{{formatDate date "full"}}
`$3
`handlebars
{{formatNumber 1234.56}}
{{formatNumber 0.15 style="percent"}}
`$3
`handlebars
{{add 10 5}}
{{subtract 10 5}}
{{multiply 10 5}}
{{divide 10 5}}
{{percentage 25 100}}
`Custom Helpers
You can define your own custom helpers in the configuration:
`typescript
pdf: {
customHelpers: {
// Simple value transformation
customFormat: (value: any) => [${value}],
// String manipulation
repeat: (str: string, times: number) => str.repeat(times || 1),
// Block helper with conditional logic
ifEquals: function(this: any, arg1: any, arg2: any, options: any) {
return (arg1 === arg2) ? options.fn(this) : options.inverse(this)
}
}
}
`Use them in templates:
`handlebars
{{customFormat "hello"}}
{{repeat "★" 5}}
{{#ifEquals status "active"}}Active User{{else}}Inactive User{{/ifEquals}}
`$3
`handlebars
{{upper "hello world"}}
{{lower "HELLO WORLD"}}
{{capitalize "hello world"}}
{{truncate "Long text here" 10}}
`$3
`handlebars
{{lineTotal quantity price}}
`Template Features
$3
The module automatically enriches your data based on template names:
Invoice Templates get:
-
subtotal - Sum of all line items
- tax - Calculated tax amount
- total - Subtotal + tax
- dueDate - Calculated from issue date + payment termsSales Report Templates get:
-
quarters - Quarterly breakdown of sales data
- rating - Performance rating based on total sales$3
Use standard CSS with print-specific rules:
`css
@page {
size: A4;
margin: 20mm;
}.page-break {
page-break-before: always;
}
@media print {
.no-break {
page-break-inside: avoid;
}
}
`$3
Create reusable components in your
sharedComponents directory:`handlebars
{{title}}
{{subtitle}}
`Use in templates:
`handlebars
{{> header title="My Document" subtitle="Generated Report"}}
`API Reference
$3
The main composable for PDF operations:
`typescript
const {
generate, // (template, data, options?, locale?) => Promise
download, // (template, data, options?, filename?, locale?) => Promise
getAvailableLocales, // () => string[]
getDefaultLocale // () => string
} = usePdf()
`$3
`typescript
interface PdfOptions {
format?: 'A4' | 'Letter' | 'Legal'
margin?: {
top?: number
bottom?: number
left?: number
right?: number
}
landscape?: boolean
printBackground?: boolean
pageBreak?: {
before?: string[]
after?: string[]
avoid?: string[]
}
}
`Development
$3
The module includes a full playground application:
`bash
npm run dev
`This starts a demo app with sample Invoice and Sales Report templates in multiple languages.
$3
`bash
npm run build
`$3
`bash
npm run test
`Examples
Check out the
playground/` directory for complete examples including:- Invoice Template - Complete invoice with line items, taxes, and totals
- Sales Report Template - Comprehensive report with metrics and quarterly breakdown
- Multi-language Support - Templates in English, Spanish, and French
- Multiple Providers - Configuration examples for all supported providers
MIT
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.
- 📖 Documentation
- 🐛 Issue Tracker
- 💬 Discussions