Native file format generators for Node.js. Produces .zip, .docx, .xlsx, and .pdf files using only built-in modules — no external dependencies.
| xd-makeFiles | docx (npm) | exceljs | pdfkit | archiver | |
|---|---|---|---|---|---|
| Install size | 0 B | ~800 KB | ~2.1 MB | ~1.5 MB | ~600 KB |
| Dependencies | 0 | 3 | 8 | 12 | 7 |
| Lines of code | ~1000 | ~12K | ~45K | ~30K | ~8K |
| Formats | zip, docx, xlsx, pdf | docx | xlsx | zip/tar |
Four modules, ~1000 lines total, zero node_modules.
xd-makeFiles/
├── index.js Unified API — makeFile('format', opts) router
├── xd-zip/ ZIP archive engine (foundation layer)
│ └── zip.js CRC32, ZIP64, store method — used by docx & xlsx
├── xd-docx/ Word document generator
│ └── docx.js OOXML WordprocessingML → ZIP container
├── xd-xls/ Excel spreadsheet generator
│ └── xls.js OOXML SpreadsheetML → ZIP container
└── xd-pdf/ PDF generator from Markdown
└── pdf.js Markdown parser → layout engine → PDF 1.4 binary
Dependency graph:
xd-docx ──→ xd-zip ←── xd-xls
xd-pdf (standalone, uses node:zlib)
import { createZip, generateZip } from './xd-zip/zip.js';
const zip = createZip();
zip.addFile('hello.txt', 'Hello World');
zip.addFile('data.json', JSON.stringify({ version: 1 }));
fs.writeFileSync('output.zip', zip.build());import { generateDocx } from './xd-docx/docx.js';
generateDocx({
outputPath: 'report.docx',
title: 'Q1 Report',
sections: [
{ type: 'heading', text: 'Summary', level: 2 },
{ type: 'text', text: 'Revenue increased 23% year-over-year.' },
{ type: 'table', rows: [['Metric', 'Value'], ['Revenue', '$1.2M'], ['Users', '45K']] },
{ type: 'list', items: ['Expand to EU', 'Launch mobile app'], ordered: true }
]
});import { generateXlsx } from './xd-xls/xls.js';
generateXlsx({
outputPath: 'data.xlsx',
sheets: [{
name: 'Sales',
data: [
['Product', 'Q1', 'Q2', 'Total'],
['Widget A', 150, 200, '=B2+C2'],
['Widget B', 300, 180, '=B3+C3']
]
}]
});import { generatePdfFromMarkdown } from './xd-pdf/pdf.js';
const markdown = `# Project Status
## Overview
Development is **on track** with *minor* delays in testing.
| Task | Status |
|------------|-----------|
| Backend | Complete |
| Frontend | In Review |
> Next milestone: v2.0 release
`;
generatePdfFromMarkdown(markdown, 'status.pdf', { title: 'Project Status' });Use index.js for unified access to all generators:
import makeFile from './index.js';
// Route by format string
makeFile('docx', {
outputPath: 'report.docx',
title: 'Q1 Report',
sections: [{ type: 'text', text: 'Revenue grew 23%.' }]
});
makeFile('xlsx', {
outputPath: 'data.xlsx',
data: [['Name', 'Score'], ['Alice', 95], ['Bob', 87]]
});
makeFile('pdf', {
outputPath: 'notes.pdf',
markdown: '# Meeting Notes\n\nAction items:\n- Ship v2\n- Hire 3 devs'
});
makeFile('zip', {
outputPath: 'bundle.zip',
files: [{ name: 'readme.txt', content: 'Hello' }]
});Or import individual generators directly:
import { generateDocx, generateXlsx, generatePdfFromMarkdown, createZip } from './index.js';Format aliases: doc → docx, xls/excel → xlsx. Auto-detection from outputPath extension when format is omitted.
Each module has its own README with full API reference and internals:
| Module | Output | LOC | Node.js deps | Docs |
|---|---|---|---|---|
| xd-zip | .zip |
~200 | node:fs |
README |
| xd-docx | .docx |
~185 | node:fs + xd-zip |
README |
| xd-xls | .xlsx |
~127 | node:fs + xd-zip |
README |
| xd-pdf | .pdf |
~500 | node:fs, node:zlib |
README |
Node.js >= 18 (uses Buffer.writeBigUInt64LE, ESM imports)
Zero dependencies — every byte of output is constructed from raw binary operations and XML string assembly. No npm packages, no transpilers, no build step.
Object literals over classes — all internal structures use factory functions and Object.create() prototypal inheritance. No class keyword anywhere.
Format-compliant output — generated files open correctly in Microsoft Office, LibreOffice, macOS Preview, and all major PDF readers. OOXML structures follow the ECMA-376 specification; PDF output conforms to PDF 1.4.
- PDF: Uses WinAnsi encoding with Type1 fonts — non-Latin characters (including Polish diacritics) are transliterated to ASCII approximations. This is a deliberate tradeoff: embedding Unicode font subsets would add ~500 LOC and require bundling
.ttffiles. - XLSX: No chart generation, conditional formatting, or pivot tables. Supports the data layer: cell types, formulas, dates, multi-sheet.
- DOCX: No headers/footers, table of contents, or page numbers. Covers the content layer: headings, paragraphs, tables, lists, images.
- ZIP: Store method only (no compression). Files within OOXML containers are XML text, so the size overhead is minimal for typical document sizes.
MIT — Jakub Śledzikowski