npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nebula-pdf-engine

v1.0.3

Published

A high-performance, server-side PDF generation library that transforms React/JSX templates into beautiful, multi-page documents—generate PDFs using React and Tailwind-like Flexbox without Headless Chrome, in a lightweight, edge-ready package that’s 100× s

Downloads

31

Readme

🌌 Nebula PDF Engine

A high-performance, server-side PDF generation library that transforms React/JSX templates into beautiful, multi-page documents—generate PDFs using React and Tailwind-like Flexbox without Headless Chrome, in a lightweight, edge-ready package that’s 100× smaller than Puppeteer.

Powered by Satori, Resvg, and pdf-lib, Nebula provides pixel-perfect layout control with the familiarity of Flexbox and JSX.

Ideal for generating dynamic invoices, automated business reports, and high-density shipping labels at the edge.

✨ Features

  • ⚛️ Standard JSX: Use <Page>, <Box>, <Text>, and <Image> with Preact.
  • 📏 Flexbox Layout: Full support for CSS Flexbox via Satori (Yoga).
  • 📄 Multi-Page Engine: Automatic content overflow detection and smart text splitting across pages.
  • 📐 Precise Measure: Control the exact content width of your pages with the contentWidth override.
  • 📊 First-Class Tables: Schema-driven tables with automatic column resolution and repeating headers.
  • 🖼️ High-Density Assets: Crisp SVG and remote image resolution via Sharp scaling (Retina ready).
  • 🦅 High Performance: Powered by a Rust-based rendering pipeline (Resvg).
  • 🎨 Custom DPI: Configure your export's device pixel ratio for the perfect balance of size and quality.

🚀 Installation

npm install nebula-pdf-engine

Note: This package requires sharp and @resvg/resvg-js, which are native dependencies.


📊 Tables (First-Class Primitive)

Nebula treats tables as layout primitives. Instead of manually building rows with boxes, you provide a schema and data.

import { Table } from 'nebula-pdf-engine';

const columns = [
  { header: 'ID', key: 'id', width: 50 },
  { header: 'Description', key: 'desc', flex: 1 },
  { header: 'Amount', key: 'amt', width: 100, align: 'right' }
];

<Table 
  columns={columns} 
  data={rows} 
  options={{ 
    stripe: true, 
    headerRepeat: true 
  }} 
/>

Highlights:

  • Header Repetition: If a table spans 10 pages, the header appears on all 10 automatically.
  • Atomic Rows: A single row will never be sliced in half across pages.
  • Flexible Widths: Mix absolute points (100), percentages ("20%"), and flex weights (flex: 1).

⚙️ TypeScript Configuration

Nebula uses Preact for its lightweight JSX runtime. To use JSX in your project, update your tsconfig.json:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "preact"
  }
}

Alternative: Without JSX

If you prefer not to use JSX or don't want to change your config, you can use the createElement function (or its alias h) directly in .ts files:

import { PdfEngine, Page, Text, createElement } from 'nebula-pdf-engine';

const pdf = await engine.generate(
  createElement(Page, { size: 'A4' }, 
    createElement(Text, { style: { fontSize: 20 } }, 'Hello Workspace!')
  )
);

🛠️ Quick Start (Standalone)

import { PdfEngine, Page, Text, Image } from 'nebula-pdf-engine';
import * as fs from 'fs';

// 1. Initialize the engine with fonts
const engine = new PdfEngine({
  fonts: [
    { name: 'Inter', data: fs.readFileSync('./fonts/Inter-Regular.ttf'), weight: 400 }
  ],
  devicePixelRatio: 2, // Retina quality
});

// 2. Generate PDF
const pdfBuffer = await engine.generate(
  <Page size="A4" padding={40}>
    <Text style={{ fontSize: 32, marginBottom: 20 }}>Hello Nebula!</Text>
    <Image src="https://example.com/logo.png" width={100} height={50} />
    <Text style={{ marginTop: 20 }}>
      This content will automatically flow across multiple pages if it's too long.
    </Text>
  </Page>
);

fs.writeFileSync('output.pdf', pdfBuffer);

📄 Multi-Page Handling

Nebula handles multi-page documents in two ways to give you maximum flexibility.

1. Automatic Overflow (Dynamic Content)

If a single <Page> contains more content than can fit, the layout engine automatically splits it. This is ideal for long text, tables, or dynamic lists.

<Page padding={40}>
  <Text>This very long text will span multiple pages automatically...</Text>
</Page>

2. Manual Pagination (Explicit Pages)

For documents with distinct sections (e.g., a Cover Page followed by a Report), you can provide multiple <Page> components:

await engine.generate(
  <>
    <Page size="A4">
      <Text>Cover Page</Text>
    </Page>
    <Page size="A4">
      <Text>Second Page with different content...</Text>
    </Page>
  </>
);

🏢 NestJS Integration

Nebula provides a NebulaPdfModule for seamless integration into NestJS environments.

1. Register the Module

@Module({
  imports: [
    NebulaPdfModule.forRoot({
      fonts: [{ name: 'Inter', data: fontBuffer, weight: 400 }],
    }),
  ],
})
export class AppModule {}

2. Inject and Use

@Injectable()
export class ReportService {
  constructor(private readonly pdfService: NebulaPdfService) {}

  async generateReport(data: any) {
    return await this.pdfService.generate(
      <Page>
        <Text>Report for {data.name}</Text>
      </Page>
    );
  }
}

📦 Component Primitives

<Page>

The top-level container.

  • size: 'A4' | 'LETTER' | 'LEGAL' (Default: A4)
  • orientation: 'portrait' | 'landscape' (Default: portrait)
  • padding: number | { top, right, bottom, left }
  • contentWidth: number. Optional. Explicitly sets the width of the content area. Useful for narrow layouts (like receipts) where you want to restrict the measure area regardless of page size.

<Box>

A generic flexbox container.

  • style: All Satori-supported flexbox properties (display: flex is default).

<Text>

Renders text strings.

  • Smart Splitting: If text exceeds the page height, the engine split it at a safe word boundary and continues on a new page.

<Image>

  • src: Absolute paths, URLs, or relative paths.
  • width / height: Required. The engine uses these to downsample the image for the PDF, significantly reducing file size.

<Table>

  • columns: Array of ColumnDefinition objects (header, key, width/flex).
  • data: Array of objects to render.
  • options: { stripe, headerRepeat, stripeColor }.
  • headerStyle / rowStyle: Style overrides for table elements.

🧠 Advanced: Layout Engine

Nebula doesn't just render a single canvas; it features a recursive Layout Engine:

  1. Measurement Pass: Every child is pre-rendered at the target width to calculate its exact content height.
  2. Bin Packing: Elements are distributed into pages according to your contentHeight.
  3. Table Pipeline: Tables trigger a specialized row-by-row pagination loop with header injection.
  4. Atomic vs Splittable: Images, Boxes, and Table Rows are "Atomic", while Text is "Splittable".

⚖️ Nebula vs Alternatives

| Category | Nebula PDF Engine | Puppeteer | pdfmake | | --- | --- | --- | --- | | Runtime footprint | Lightweight package; no bundled browser binary (typically orders of magnitude smaller than Chromium-based stacks) | Heavy Chromium dependency; large runtime and deployment artifact | Lightweight JS library; smaller than browser-based renderers | | Styling model | JSX + Flexbox-style layout (<Page>, <Box>, <Text>, <Image>, <Table>) | Full HTML/CSS via headless browser rendering | JSON document-definition API with limited CSS-like styling | | Edge / Serverless fit | Designed for server-side and edge-friendly runtimes (no browser process required) | Weaker fit for edge/serverless due to browser process, memory, and cold-start overhead | Good serverless fit for Node environments; not JSX/Flexbox-native | | Layout engine | Deterministic layout with measurement + pagination, atomic rows, smart text splitting | Browser print/layout engine (powerful but heavier and less predictable for print workflows) | Declarative PDF primitives (tables, columns, stacks) with less web-like layout behavior |


📜 License

MIT