pdf-creator-node 2.4.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/createPdf.d.ts +3 -3
- package/dist/createPdf.d.ts.map +1 -1
- package/dist/createPdf.js +20 -45
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/pdfChrome.d.ts +12 -0
- package/dist/pdfChrome.d.ts.map +1 -0
- package/dist/pdfChrome.js +117 -0
- package/dist/pdfPuppeteer.d.ts +11 -0
- package/dist/pdfPuppeteer.d.ts.map +1 -0
- package/dist/pdfPuppeteer.js +154 -0
- package/dist/pdfRenderOptions.d.ts +65 -0
- package/dist/pdfRenderOptions.d.ts.map +1 -0
- package/dist/pdfRenderOptions.js +2 -0
- package/dist/types.d.ts +43 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/readme.md +47 -8
package/dist/createPdf.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { FileInfo } from "html-pdf";
|
|
2
1
|
import type { PdfCreateOptions, PdfDocument } from "./types";
|
|
2
|
+
import type { PdfFileInfo } from "./pdfRenderOptions";
|
|
3
3
|
/**
|
|
4
|
-
* Renders the Handlebars template and generates a PDF via
|
|
4
|
+
* Renders the Handlebars template and generates a PDF via Puppeteer (headless Chromium).
|
|
5
5
|
*/
|
|
6
|
-
export declare function create(document: PdfDocument, options: PdfCreateOptions): Promise<Buffer | NodeJS.ReadableStream |
|
|
6
|
+
export declare function create(document: PdfDocument, options: PdfCreateOptions): Promise<Buffer | NodeJS.ReadableStream | PdfFileInfo>;
|
|
7
7
|
//# sourceMappingURL=createPdf.d.ts.map
|
package/dist/createPdf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createPdf.d.ts","sourceRoot":"","sources":["../src/createPdf.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"createPdf.d.ts","sourceRoot":"","sources":["../src/createPdf.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAmBtD;;GAEG;AACH,wBAAgB,MAAM,CACpB,QAAQ,EAAE,WAAW,EACrB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,cAAc,GAAG,WAAW,CAAC,CA2BvD"}
|
package/dist/createPdf.js
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
return t;
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
12
10
|
};
|
|
13
11
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
@@ -16,13 +14,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
16
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
15
|
exports.create = create;
|
|
18
16
|
const handlebars_1 = __importDefault(require("handlebars"));
|
|
19
|
-
const
|
|
17
|
+
const pdfPuppeteer_1 = require("./pdfPuppeteer");
|
|
18
|
+
const pdfChrome_1 = require("./pdfChrome");
|
|
20
19
|
const registerHandlebarsHelpers_1 = require("./registerHandlebarsHelpers");
|
|
21
20
|
const validation_1 = require("./validation");
|
|
22
|
-
function stripHtmlPdfOptions(options) {
|
|
23
|
-
const { handlebarsHelpers: _h } = options, rest = __rest(options, ["handlebarsHelpers"]);
|
|
24
|
-
return rest;
|
|
25
|
-
}
|
|
26
21
|
function renderHtml(document, options) {
|
|
27
22
|
const hb = handlebars_1.default.create();
|
|
28
23
|
(0, registerHandlebarsHelpers_1.registerHandlebarsHelpers)(hb);
|
|
@@ -40,52 +35,32 @@ function renderHtml(document, options) {
|
|
|
40
35
|
}
|
|
41
36
|
}
|
|
42
37
|
/**
|
|
43
|
-
* Renders the Handlebars template and generates a PDF via
|
|
38
|
+
* Renders the Handlebars template and generates a PDF via Puppeteer (headless Chromium).
|
|
44
39
|
*/
|
|
45
40
|
function create(document, options) {
|
|
46
|
-
return
|
|
41
|
+
return (() => __awaiter(this, void 0, void 0, function* () {
|
|
47
42
|
try {
|
|
48
43
|
(0, validation_1.validatePdfDocument)(document);
|
|
49
44
|
}
|
|
50
45
|
catch (e) {
|
|
51
|
-
|
|
52
|
-
return;
|
|
46
|
+
throw e;
|
|
53
47
|
}
|
|
54
48
|
let html;
|
|
55
49
|
try {
|
|
56
50
|
html = renderHtml(document, options);
|
|
57
51
|
}
|
|
58
52
|
catch (e) {
|
|
59
|
-
|
|
60
|
-
return;
|
|
53
|
+
throw e;
|
|
61
54
|
}
|
|
62
|
-
const pdfOptions =
|
|
63
|
-
const
|
|
55
|
+
const pdfOptions = (0, pdfChrome_1.mergePdfCreateOptions)(options);
|
|
56
|
+
const buffer = yield (0, pdfPuppeteer_1.renderPdfToBuffer)(html, pdfOptions);
|
|
64
57
|
switch (document.type) {
|
|
65
58
|
case "buffer":
|
|
66
|
-
|
|
67
|
-
if (err)
|
|
68
|
-
reject(err);
|
|
69
|
-
else
|
|
70
|
-
resolve(res);
|
|
71
|
-
});
|
|
72
|
-
break;
|
|
59
|
+
return buffer;
|
|
73
60
|
case "stream":
|
|
74
|
-
|
|
75
|
-
if (err)
|
|
76
|
-
reject(err);
|
|
77
|
-
else
|
|
78
|
-
resolve(res);
|
|
79
|
-
});
|
|
80
|
-
break;
|
|
61
|
+
return (0, pdfPuppeteer_1.bufferToStream)(buffer);
|
|
81
62
|
default:
|
|
82
|
-
|
|
83
|
-
if (err)
|
|
84
|
-
reject(err);
|
|
85
|
-
else
|
|
86
|
-
resolve(res);
|
|
87
|
-
});
|
|
88
|
-
break;
|
|
63
|
+
return (0, pdfPuppeteer_1.writePdfToFile)(document.path, buffer);
|
|
89
64
|
}
|
|
90
|
-
});
|
|
65
|
+
}))();
|
|
91
66
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,11 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { create } from "./createPdf";
|
|
5
5
|
export { create };
|
|
6
|
-
export
|
|
6
|
+
export { buildPdfChrome } from "./pdfChrome";
|
|
7
|
+
export { htmlPdfTokensToPuppeteer } from "./pdfPuppeteer";
|
|
8
|
+
export type { Document, IfCondOptions, PdfChromeOptions, PdfCreateOptions, PdfDocument, PdfDocumentBuffer, PdfDocumentFile, PdfDocumentStream, PdfFooterConfig, PdfHeaderConfig, PdfLayout, } from "./types";
|
|
9
|
+
export type { PdfFileInfo, PdfRenderOptions } from "./pdfRenderOptions";
|
|
10
|
+
export type { PdfFileInfo as FileInfo } from "./pdfRenderOptions";
|
|
7
11
|
declare const api: {
|
|
8
12
|
create: typeof create;
|
|
9
13
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,YAAY,EACV,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAIrC,OAAO,EAAE,MAAM,EAAE,CAAC;AAClB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,YAAY,EACV,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,SAAS,GACV,MAAM,SAAS,CAAC;AACjB,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACxE,YAAY,EAAE,WAAW,IAAI,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAElE,QAAA,MAAM,GAAG;;CAAa,CAAC;AACvB,eAAe,GAAG,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -3,10 +3,14 @@
|
|
|
3
3
|
* @author Shyam Hajare <hajareshyam@gmail.com>
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.create = void 0;
|
|
6
|
+
exports.htmlPdfTokensToPuppeteer = exports.buildPdfChrome = exports.create = void 0;
|
|
7
7
|
const registerHandlebarsHelpers_1 = require("./registerHandlebarsHelpers");
|
|
8
8
|
const createPdf_1 = require("./createPdf");
|
|
9
9
|
Object.defineProperty(exports, "create", { enumerable: true, get: function () { return createPdf_1.create; } });
|
|
10
10
|
(0, registerHandlebarsHelpers_1.registerHandlebarsHelpers)();
|
|
11
|
+
var pdfChrome_1 = require("./pdfChrome");
|
|
12
|
+
Object.defineProperty(exports, "buildPdfChrome", { enumerable: true, get: function () { return pdfChrome_1.buildPdfChrome; } });
|
|
13
|
+
var pdfPuppeteer_1 = require("./pdfPuppeteer");
|
|
14
|
+
Object.defineProperty(exports, "htmlPdfTokensToPuppeteer", { enumerable: true, get: function () { return pdfPuppeteer_1.htmlPdfTokensToPuppeteer; } });
|
|
11
15
|
const api = { create: createPdf_1.create };
|
|
12
16
|
exports.default = api;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PdfChromeOptions, PdfCreateOptions } from "./types";
|
|
2
|
+
import type { PdfRenderOptions } from "./pdfRenderOptions";
|
|
3
|
+
/**
|
|
4
|
+
* Builds partial html-pdf options from layout / header / footer / copyright.
|
|
5
|
+
* Use {@link mergePdfCreateOptions} to merge with explicit `format`, `header`, `footer`.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildPdfChrome(chrome?: PdfChromeOptions): Partial<PdfRenderOptions>;
|
|
8
|
+
/**
|
|
9
|
+
* Merges `pdfChrome` with explicit PDF options. Explicit `header` / `footer` / `format` win.
|
|
10
|
+
*/
|
|
11
|
+
export declare function mergePdfCreateOptions(options: PdfCreateOptions): PdfRenderOptions;
|
|
12
|
+
//# sourceMappingURL=pdfChrome.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdfChrome.d.ts","sourceRoot":"","sources":["../src/pdfChrome.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AA+C3D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuDnF;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,gBAAgB,CASjF"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.buildPdfChrome = buildPdfChrome;
|
|
15
|
+
exports.mergePdfCreateOptions = mergePdfCreateOptions;
|
|
16
|
+
function escapeHtml(s) {
|
|
17
|
+
return s
|
|
18
|
+
.replace(/&/g, "&")
|
|
19
|
+
.replace(/</g, "<")
|
|
20
|
+
.replace(/>/g, ">")
|
|
21
|
+
.replace(/"/g, """);
|
|
22
|
+
}
|
|
23
|
+
function defaultHeaderHtml(title) {
|
|
24
|
+
return `<div style="text-align:center;font-size:10px;padding:6px;">${escapeHtml(title)}</div>`;
|
|
25
|
+
}
|
|
26
|
+
function buildFooterContents(copyright, showPageNumbers) {
|
|
27
|
+
const hasCopyright = copyright != null && String(copyright).trim() !== "";
|
|
28
|
+
const pagePart = showPageNumbers
|
|
29
|
+
? '<span style="color:#444">{{page}}</span>/<span>{{pages}}</span>'
|
|
30
|
+
: "";
|
|
31
|
+
if (hasCopyright && pagePart) {
|
|
32
|
+
return {
|
|
33
|
+
default: `<div style="text-align:center;font-size:9px;padding:4px;">${escapeHtml(String(copyright))} · ${pagePart}</div>`,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (hasCopyright) {
|
|
37
|
+
return {
|
|
38
|
+
default: `<div style="text-align:center;font-size:9px;padding:4px;">${escapeHtml(String(copyright))}</div>`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (pagePart) {
|
|
42
|
+
return {
|
|
43
|
+
default: `<div style="text-align:center;font-size:9px;padding:4px;">${pagePart}</div>`,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return { default: "" };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Builds partial html-pdf options from layout / header / footer / copyright.
|
|
50
|
+
* Use {@link mergePdfCreateOptions} to merge with explicit `format`, `header`, `footer`.
|
|
51
|
+
*/
|
|
52
|
+
function buildPdfChrome(chrome) {
|
|
53
|
+
var _a, _b, _c, _d;
|
|
54
|
+
if (!chrome)
|
|
55
|
+
return {};
|
|
56
|
+
const out = {};
|
|
57
|
+
if (chrome.layout) {
|
|
58
|
+
const L = chrome.layout;
|
|
59
|
+
if (L.format)
|
|
60
|
+
out.format = L.format;
|
|
61
|
+
if (L.orientation)
|
|
62
|
+
out.orientation = L.orientation;
|
|
63
|
+
if (L.width)
|
|
64
|
+
out.width = L.width;
|
|
65
|
+
if (L.height)
|
|
66
|
+
out.height = L.height;
|
|
67
|
+
if (L.border !== undefined)
|
|
68
|
+
out.border = L.border;
|
|
69
|
+
}
|
|
70
|
+
if (chrome.header) {
|
|
71
|
+
const h = chrome.header;
|
|
72
|
+
const contents = (_a = h.html) !== null && _a !== void 0 ? _a : (h.title != null && h.title !== "" ? defaultHeaderHtml(h.title) : undefined);
|
|
73
|
+
if (contents) {
|
|
74
|
+
out.header = {
|
|
75
|
+
height: (_b = h.height) !== null && _b !== void 0 ? _b : "45mm",
|
|
76
|
+
contents,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else if (h.height) {
|
|
80
|
+
out.header = { height: h.height };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (chrome.footer) {
|
|
84
|
+
const f = chrome.footer;
|
|
85
|
+
if (f.html) {
|
|
86
|
+
out.footer = {
|
|
87
|
+
height: (_c = f.height) !== null && _c !== void 0 ? _c : "28mm",
|
|
88
|
+
contents: { default: f.html },
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const hasCopyright = f.copyright != null && String(f.copyright).trim() !== "";
|
|
93
|
+
const showPages = f.showPageNumbers === true ||
|
|
94
|
+
(f.showPageNumbers !== false && hasCopyright);
|
|
95
|
+
if (hasCopyright || showPages) {
|
|
96
|
+
const contents = buildFooterContents(hasCopyright ? String(f.copyright) : undefined, showPages);
|
|
97
|
+
out.footer = {
|
|
98
|
+
height: (_d = f.height) !== null && _d !== void 0 ? _d : "28mm",
|
|
99
|
+
contents,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
else if (f.height) {
|
|
103
|
+
out.footer = { height: f.height };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Merges `pdfChrome` with explicit PDF options. Explicit `header` / `footer` / `format` win.
|
|
111
|
+
*/
|
|
112
|
+
function mergePdfCreateOptions(options) {
|
|
113
|
+
var _a, _b;
|
|
114
|
+
const { handlebarsHelpers: _h, pdfChrome } = options, userPdfOptions = __rest(options, ["handlebarsHelpers", "pdfChrome"]);
|
|
115
|
+
const fromChrome = buildPdfChrome(pdfChrome);
|
|
116
|
+
return Object.assign(Object.assign(Object.assign({}, fromChrome), userPdfOptions), { header: (_a = userPdfOptions.header) !== null && _a !== void 0 ? _a : fromChrome.header, footer: (_b = userPdfOptions.footer) !== null && _b !== void 0 ? _b : fromChrome.footer });
|
|
117
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Readable } from "stream";
|
|
2
|
+
import type { PdfFileInfo, PdfRenderOptions } from "./pdfRenderOptions";
|
|
3
|
+
/** Maps html-pdf `{{page}}` / `{{pages}}` to Puppeteer header/footer template tokens. */
|
|
4
|
+
export declare function htmlPdfTokensToPuppeteer(html: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Renders HTML to PDF bytes using headless Chromium (Puppeteer).
|
|
7
|
+
*/
|
|
8
|
+
export declare function renderPdfToBuffer(html: string, options: PdfRenderOptions): Promise<Buffer>;
|
|
9
|
+
export declare function writePdfToFile(path: string, buffer: Buffer): Promise<PdfFileInfo>;
|
|
10
|
+
export declare function bufferToStream(buffer: Buffer): Readable;
|
|
11
|
+
//# sourceMappingURL=pdfPuppeteer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdfPuppeteer.d.ts","sourceRoot":"","sources":["../src/pdfPuppeteer.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAExE,yFAAyF;AACzF,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAI7D;AA8FD;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CA4BjB;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAItB;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAEvD"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.htmlPdfTokensToPuppeteer = htmlPdfTokensToPuppeteer;
|
|
16
|
+
exports.renderPdfToBuffer = renderPdfToBuffer;
|
|
17
|
+
exports.writePdfToFile = writePdfToFile;
|
|
18
|
+
exports.bufferToStream = bufferToStream;
|
|
19
|
+
const promises_1 = require("fs/promises");
|
|
20
|
+
const path_1 = require("path");
|
|
21
|
+
const puppeteer_1 = __importDefault(require("puppeteer"));
|
|
22
|
+
const stream_1 = require("stream");
|
|
23
|
+
/** Maps html-pdf `{{page}}` / `{{pages}}` to Puppeteer header/footer template tokens. */
|
|
24
|
+
function htmlPdfTokensToPuppeteer(html) {
|
|
25
|
+
return html
|
|
26
|
+
.replace(/\{\{\s*page\s*\}\}/gi, '<span class="pageNumber"></span>')
|
|
27
|
+
.replace(/\{\{\s*pages\s*\}\}/gi, '<span class="totalPages"></span>');
|
|
28
|
+
}
|
|
29
|
+
function wrapPrintTemplate(html) {
|
|
30
|
+
return `<div style="font-size:10px;width:100%;box-sizing:border-box;padding:4px 12px;">${htmlPdfTokensToPuppeteer(html)}</div>`;
|
|
31
|
+
}
|
|
32
|
+
function borderToMargin(border) {
|
|
33
|
+
var _a, _b, _c, _d;
|
|
34
|
+
if (border == null)
|
|
35
|
+
return undefined;
|
|
36
|
+
if (typeof border === "string") {
|
|
37
|
+
return { top: border, right: border, bottom: border, left: border };
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
top: (_a = border.top) !== null && _a !== void 0 ? _a : "0",
|
|
41
|
+
right: (_b = border.right) !== null && _b !== void 0 ? _b : "0",
|
|
42
|
+
bottom: (_c = border.bottom) !== null && _c !== void 0 ? _c : "0",
|
|
43
|
+
left: (_d = border.left) !== null && _d !== void 0 ? _d : "0",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function ensureFullHtmlDocument(html) {
|
|
47
|
+
const trimmed = html.trim();
|
|
48
|
+
if (/^<!DOCTYPE/i.test(trimmed) || /<html[\s>]/i.test(trimmed)) {
|
|
49
|
+
return html;
|
|
50
|
+
}
|
|
51
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>${html}</body></html>`;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* v4+: Puppeteer only supports one footer template — we use `default`, else `first`, else `last`.
|
|
55
|
+
* Per-page numeric keys are ignored.
|
|
56
|
+
*/
|
|
57
|
+
function pickFooterHtml(footer) {
|
|
58
|
+
const c = footer === null || footer === void 0 ? void 0 : footer.contents;
|
|
59
|
+
if (!c)
|
|
60
|
+
return undefined;
|
|
61
|
+
if (c.default != null && String(c.default).trim() !== "")
|
|
62
|
+
return String(c.default);
|
|
63
|
+
if (c.first != null && String(c.first).trim() !== "")
|
|
64
|
+
return String(c.first);
|
|
65
|
+
if (c.last != null && String(c.last).trim() !== "")
|
|
66
|
+
return String(c.last);
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
function withBrowser(fn) {
|
|
70
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
71
|
+
const browser = yield puppeteer_1.default.launch({
|
|
72
|
+
headless: true,
|
|
73
|
+
args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"],
|
|
74
|
+
});
|
|
75
|
+
try {
|
|
76
|
+
return yield fn(browser);
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
yield browser.close();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function buildPdfOptions(opts) {
|
|
84
|
+
var _a, _b;
|
|
85
|
+
const margin = borderToMargin(opts.border);
|
|
86
|
+
const headerHtml = (_a = opts.header) === null || _a === void 0 ? void 0 : _a.contents;
|
|
87
|
+
const footerHtml = pickFooterHtml(opts.footer);
|
|
88
|
+
const hasHeader = Boolean(headerHtml && headerHtml.trim());
|
|
89
|
+
const hasFooter = Boolean(footerHtml && footerHtml.trim());
|
|
90
|
+
const format = opts.width && opts.height ? undefined : (_b = opts.format) !== null && _b !== void 0 ? _b : "A4";
|
|
91
|
+
const landscape = opts.orientation === "landscape";
|
|
92
|
+
const pdfOpts = {
|
|
93
|
+
printBackground: true,
|
|
94
|
+
landscape,
|
|
95
|
+
};
|
|
96
|
+
if (hasHeader || hasFooter) {
|
|
97
|
+
pdfOpts.displayHeaderFooter = true;
|
|
98
|
+
pdfOpts.headerTemplate = hasHeader
|
|
99
|
+
? wrapPrintTemplate(headerHtml)
|
|
100
|
+
: "<span></span>";
|
|
101
|
+
pdfOpts.footerTemplate = hasFooter
|
|
102
|
+
? wrapPrintTemplate(footerHtml)
|
|
103
|
+
: "<span></span>";
|
|
104
|
+
}
|
|
105
|
+
if (margin) {
|
|
106
|
+
pdfOpts.margin = margin;
|
|
107
|
+
}
|
|
108
|
+
if (opts.width && opts.height) {
|
|
109
|
+
pdfOpts.width = opts.width;
|
|
110
|
+
pdfOpts.height = opts.height;
|
|
111
|
+
}
|
|
112
|
+
else if (format) {
|
|
113
|
+
pdfOpts.format = format;
|
|
114
|
+
}
|
|
115
|
+
return pdfOpts;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Renders HTML to PDF bytes using headless Chromium (Puppeteer).
|
|
119
|
+
*/
|
|
120
|
+
function renderPdfToBuffer(html, options) {
|
|
121
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
122
|
+
var _a;
|
|
123
|
+
const fullHtml = ensureFullHtmlDocument(html);
|
|
124
|
+
const pdfOpts = buildPdfOptions(options);
|
|
125
|
+
const timeout = (_a = options.timeout) !== null && _a !== void 0 ? _a : 30000;
|
|
126
|
+
return withBrowser((browser) => __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
var _a;
|
|
128
|
+
const page = yield browser.newPage();
|
|
129
|
+
page.setDefaultTimeout(timeout);
|
|
130
|
+
if (options.httpHeaders && Object.keys(options.httpHeaders).length > 0) {
|
|
131
|
+
yield page.setExtraHTTPHeaders(options.httpHeaders);
|
|
132
|
+
}
|
|
133
|
+
if ((_a = options.httpCookies) === null || _a === void 0 ? void 0 : _a.length) {
|
|
134
|
+
yield page.setCookie(...options.httpCookies);
|
|
135
|
+
}
|
|
136
|
+
yield page.setContent(fullHtml, Object.assign({ waitUntil: "load", timeout }, (options.base ? { baseURL: options.base } : {})));
|
|
137
|
+
if (typeof options.renderDelay === "number" && options.renderDelay > 0) {
|
|
138
|
+
yield new Promise((r) => setTimeout(r, options.renderDelay));
|
|
139
|
+
}
|
|
140
|
+
const buf = yield page.pdf(pdfOpts);
|
|
141
|
+
return Buffer.from(buf);
|
|
142
|
+
}));
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function writePdfToFile(path, buffer) {
|
|
146
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
147
|
+
yield (0, promises_1.mkdir)((0, path_1.dirname)(path), { recursive: true });
|
|
148
|
+
yield (0, promises_1.writeFile)(path, buffer);
|
|
149
|
+
return { filename: path };
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function bufferToStream(buffer) {
|
|
153
|
+
return stream_1.Readable.from(buffer);
|
|
154
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PDF engine options (formerly html-pdf / PhantomJS; now mapped to Puppeteer).
|
|
3
|
+
* Kept compatible with the previous option shape where possible.
|
|
4
|
+
*/
|
|
5
|
+
export interface PdfRenderOptions {
|
|
6
|
+
directory?: string;
|
|
7
|
+
height?: string;
|
|
8
|
+
width?: string;
|
|
9
|
+
format?: "A3" | "A4" | "A5" | "Legal" | "Letter" | "Tabloid";
|
|
10
|
+
orientation?: "portrait" | "landscape";
|
|
11
|
+
border?: string | {
|
|
12
|
+
top?: string;
|
|
13
|
+
right?: string;
|
|
14
|
+
bottom?: string;
|
|
15
|
+
left?: string;
|
|
16
|
+
};
|
|
17
|
+
paginationOffset?: number;
|
|
18
|
+
header?: {
|
|
19
|
+
height?: string;
|
|
20
|
+
contents?: string;
|
|
21
|
+
};
|
|
22
|
+
footer?: {
|
|
23
|
+
height?: string;
|
|
24
|
+
contents?: {
|
|
25
|
+
first?: string;
|
|
26
|
+
[page: number]: string | undefined;
|
|
27
|
+
default?: string;
|
|
28
|
+
last?: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
base?: string;
|
|
32
|
+
zoomFactor?: string;
|
|
33
|
+
type?: "png" | "jpeg" | "pdf";
|
|
34
|
+
quality?: string;
|
|
35
|
+
/** @deprecated No effect in v4 (Puppeteer). */
|
|
36
|
+
phantomPath?: string;
|
|
37
|
+
/** @deprecated No effect in v4 (Puppeteer). */
|
|
38
|
+
phantomArgs?: string[];
|
|
39
|
+
/** @deprecated No effect in v4 (Puppeteer). */
|
|
40
|
+
localUrlAccess?: boolean;
|
|
41
|
+
/** @deprecated No effect in v4 (Puppeteer). */
|
|
42
|
+
script?: string;
|
|
43
|
+
timeout?: number;
|
|
44
|
+
renderDelay?: "manual" | number;
|
|
45
|
+
httpHeaders?: {
|
|
46
|
+
[header: string]: string;
|
|
47
|
+
};
|
|
48
|
+
childProcessOptions?: {
|
|
49
|
+
detached?: boolean;
|
|
50
|
+
};
|
|
51
|
+
httpCookies?: Array<{
|
|
52
|
+
name: string;
|
|
53
|
+
value: string;
|
|
54
|
+
domain?: string;
|
|
55
|
+
path: string;
|
|
56
|
+
httponly?: boolean;
|
|
57
|
+
secure?: boolean;
|
|
58
|
+
expires?: number;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
/** Result shape when writing to disk (same as previous html-pdf FileInfo). */
|
|
62
|
+
export interface PdfFileInfo {
|
|
63
|
+
filename: string;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=pdfRenderOptions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdfRenderOptions.d.ts","sourceRoot":"","sources":["../src/pdfRenderOptions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC7D,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IACvC,MAAM,CAAC,EACH,MAAM,GACN;QACE,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACN,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE;YACT,KAAK,CAAC,EAAE,MAAM,CAAC;YACf,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;YACnC,OAAO,CAAC,EAAE,MAAM,CAAC;YACjB,IAAI,CAAC,EAAE,MAAM,CAAC;SACf,CAAC;KACH,CAAC;IACF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAChC,WAAW,CAAC,EAAE;QACZ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;KAC1B,CAAC;IACF,mBAAmB,CAAC,EAAE;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;IACF,WAAW,CAAC,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ;AAED,8EAA8E;AAC9E,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { CreateOptions } from "html-pdf";
|
|
2
1
|
import type { HelperDelegate } from "handlebars";
|
|
2
|
+
import type { PdfRenderOptions } from "./pdfRenderOptions";
|
|
3
3
|
/** Options passed to Handlebars `ifCond` helper inverse/fn blocks */
|
|
4
4
|
export interface IfCondOptions {
|
|
5
5
|
fn: (context: any) => string;
|
|
@@ -29,11 +29,51 @@ export interface PdfDocumentStream {
|
|
|
29
29
|
export type PdfDocument = PdfDocumentFile | PdfDocumentBuffer | PdfDocumentStream;
|
|
30
30
|
/** @deprecated Use `PdfDocument` — kept for compatibility with earlier typings */
|
|
31
31
|
export type Document = PdfDocument;
|
|
32
|
+
/** Page size / margins — maps to PDF engine paper options */
|
|
33
|
+
export interface PdfLayout {
|
|
34
|
+
format?: "A3" | "A4" | "A5" | "Legal" | "Letter" | "Tabloid";
|
|
35
|
+
orientation?: "portrait" | "landscape";
|
|
36
|
+
width?: string;
|
|
37
|
+
height?: string;
|
|
38
|
+
border?: PdfRenderOptions["border"];
|
|
39
|
+
}
|
|
40
|
+
/** Repeating header — use `html` or a plain `title` (escaped) */
|
|
41
|
+
export interface PdfHeaderConfig {
|
|
42
|
+
height?: string;
|
|
43
|
+
/** Raw HTML shown on each page */
|
|
44
|
+
html?: string;
|
|
45
|
+
/** Centered plain text (HTML-escaped). Ignored if `html` is set */
|
|
46
|
+
title?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Repeating footer — use `html`, or `copyright` / `showPageNumbers` */
|
|
49
|
+
export interface PdfFooterConfig {
|
|
50
|
+
height?: string;
|
|
51
|
+
/** Raw HTML for the default footer slot */
|
|
52
|
+
html?: string;
|
|
53
|
+
/** Plain copyright line (HTML-escaped) */
|
|
54
|
+
copyright?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Include `{{page}}` / `{{pages}}`. If `copyright` is set, defaults to true unless `false`.
|
|
57
|
+
* For page numbers only, set `showPageNumbers: true` and omit `copyright`.
|
|
58
|
+
*/
|
|
59
|
+
showPageNumbers?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* High-level layout + header/footer/copyright. Merged before PDF render; any
|
|
63
|
+
* explicit `format`, `header`, `footer` on the same options object overrides these.
|
|
64
|
+
*/
|
|
65
|
+
export interface PdfChromeOptions {
|
|
66
|
+
layout?: PdfLayout;
|
|
67
|
+
header?: PdfHeaderConfig;
|
|
68
|
+
footer?: PdfFooterConfig;
|
|
69
|
+
}
|
|
32
70
|
/**
|
|
33
|
-
*
|
|
71
|
+
* PDF engine options (Puppeteer / Chromium), plus optional Handlebars helpers for this render only
|
|
34
72
|
* (rendering uses an isolated Handlebars instance).
|
|
35
73
|
*/
|
|
36
|
-
export type PdfCreateOptions =
|
|
74
|
+
export type PdfCreateOptions = PdfRenderOptions & {
|
|
37
75
|
handlebarsHelpers?: Record<string, HelperDelegate>;
|
|
76
|
+
/** Convenience presets merged into PDF options (explicit keys override) */
|
|
77
|
+
pdfChrome?: PdfChromeOptions;
|
|
38
78
|
};
|
|
39
79
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,qEAAqE;AACrE,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;IAC7B,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,MAAM,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;CACpB;AAED,0BAA0B;AAC1B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,+BAA+B;AAC/B,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,GAAG,CAAC;IACV,IAAI,EAAE,QAAQ,CAAC;CAChB;AAED,MAAM,MAAM,WAAW,GACnB,eAAe,GACf,iBAAiB,GACjB,iBAAiB,CAAC;AAEtB,kFAAkF;AAClF,MAAM,MAAM,QAAQ,GAAG,WAAW,CAAC;AAEnC,6DAA6D;AAC7D,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC7D,WAAW,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACrC;AAED,iEAAiE;AACjE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG,gBAAgB,GAAG;IAChD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnD,2EAA2E;IAC3E,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pdf-creator-node",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "node pdf creator",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"html2pdf",
|
|
31
31
|
"html-to-pdf",
|
|
32
32
|
"handlebars",
|
|
33
|
-
"
|
|
33
|
+
"puppeteer",
|
|
34
|
+
"chromium",
|
|
34
35
|
"nodejs",
|
|
35
36
|
"express",
|
|
36
37
|
"report",
|
|
@@ -40,10 +41,9 @@
|
|
|
40
41
|
"license": "MIT",
|
|
41
42
|
"dependencies": {
|
|
42
43
|
"handlebars": "^4.7.7",
|
|
43
|
-
"
|
|
44
|
+
"puppeteer": "^24.0.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"@types/html-pdf": "^3.0.3",
|
|
47
47
|
"@types/node": "^22.13.0",
|
|
48
48
|
"tsx": "^4.19.2",
|
|
49
49
|
"typescript": "^5.7.3"
|
package/readme.md
CHANGED
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
# pdf-creator-node
|
|
2
2
|
|
|
3
|
-
Convert **HTML + Handlebars** templates to **PDF** in Node.js
|
|
3
|
+
Convert **HTML + Handlebars** templates to **PDF** in Node.js using **[Puppeteer](https://pptr.dev/)** (headless **Chromium**). PhantomJS / `html-pdf` are no longer used as of **v4**.
|
|
4
4
|
|
|
5
5
|
**Requirements:** [Node.js](https://nodejs.org/) 18 or newer.
|
|
6
6
|
|
|
7
|
+
**Install size:** `puppeteer` downloads a compatible Chromium build on `npm install` (hundreds of MB). In CI you can cache the browser directory or set [`PUPPETEER_CACHE_DIR`](https://pptr.dev/guides/configuration) / `PUPPETEER_SKIP_DOWNLOAD` as needed.
|
|
8
|
+
|
|
9
|
+
### Strengths and trade-offs
|
|
10
|
+
|
|
11
|
+
| | |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| **Strengths** | **HTML + Handlebars** — quick to build **invoices, reports, and letters** without drawing coordinates. **v4+** uses **Chromium**, so you get **modern CSS** (flexbox, grid, web fonts) and a **maintained** rendering stack — not deprecated PhantomJS. **`pdfChrome`** helps with layout, headers, footers, and copyright in one place. |
|
|
14
|
+
| **Trade-offs** | **Footprint:** Chromium adds install size and **RAM** per browser instance. **Throughput:** launching a browser is heavier than a pure-JS library like **PDFKit** for tiny one-off jobs; for **high volume**, reuse browsers ([Puppeteer patterns](https://pptr.dev/)), queue work, or run workers. **Model:** this package is **HTML → PDF**; if you need a **drawing API** (paths, precise vector control) without HTML, use PDFKit / pdf-lib instead. **Print pipeline:** PDFs use Chrome’s **print** path — edge cases can differ from on-screen CSS (true for any headless-Chrome PDF approach). |
|
|
15
|
+
|
|
16
|
+
**Practical verdict:** strong fit for **small and medium** projects and **production** workloads where you control **memory** and **concurrency**; for **very large scale** (always-on millions of PDFs/day), plan **infrastructure** (pooling, autoscaling, or a dedicated rendering service) like any Chromium-based pipeline.
|
|
17
|
+
|
|
18
|
+
### Upgrading from v2.x (Phantom / html-pdf)
|
|
19
|
+
|
|
20
|
+
- **v4** is a **major** release: PDFs are rendered with Chromium, so layout can differ slightly from Phantom.
|
|
21
|
+
- Options are still the same shape for most fields (`format`, `orientation`, `border`, `header`, `footer`, `pdfChrome`).
|
|
22
|
+
- **Footer `contents`:** only one template is applied. We use `default`, else `first`, else `last`. Per-page keys (e.g. page `2`) are **not** supported in v4.
|
|
23
|
+
- **`phantomPath`**, **`phantomArgs`**, etc. are **ignored** (see `PdfRenderOptions` in types).
|
|
24
|
+
- `{{page}}` / `{{pages}}` in header/footer HTML are converted to Puppeteer’s print tokens automatically.
|
|
25
|
+
|
|
7
26
|
## Install
|
|
8
27
|
|
|
9
28
|
```bash
|
|
@@ -63,9 +82,31 @@ await pdf.create(document, options);
|
|
|
63
82
|
- **Buffer:** `type: "buffer"`.
|
|
64
83
|
- **Stream:** `type: "stream"`.
|
|
65
84
|
|
|
85
|
+
### Layout, header, footer, and copyright (`pdfChrome`)
|
|
86
|
+
|
|
87
|
+
Use **`pdfChrome`** on the second argument for common paper layout and repeating header/footer. Plain `title` / `copyright` strings are HTML-escaped.
|
|
88
|
+
|
|
89
|
+
- **`layout`:** `format`, `orientation`, `width`, `height`, `border` (mapped to Puppeteer’s PDF / margin options).
|
|
90
|
+
- **`header`:** `html` (raw HTML per page) **or** `title` (centered text). Default height `45mm` when content is set.
|
|
91
|
+
- **`footer`:** `html` **or** combine **`copyright`** with optional **`showPageNumbers`** (`{{page}}` / `{{pages}}`). With `copyright` only, page numbers default **on** unless you set `showPageNumbers: false`. For **page numbers only**, set `showPageNumbers: true` and omit `copyright`. Default footer height `28mm` when content is set.
|
|
92
|
+
|
|
93
|
+
Anything you set directly on the options object (`format`, `header`, `footer`, …) **overrides** the matching field from `pdfChrome`.
|
|
94
|
+
|
|
95
|
+
```javascript
|
|
96
|
+
pdf.create(document, {
|
|
97
|
+
pdfChrome: {
|
|
98
|
+
layout: { format: "A4", orientation: "portrait", border: "12mm" },
|
|
99
|
+
header: { title: "Quarterly report" },
|
|
100
|
+
footer: { copyright: "© 2026 My Company", showPageNumbers: true },
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Advanced: `buildPdfChrome(pdfChrome)` returns partial `PdfRenderOptions` if you want to compose manually (also exported).
|
|
106
|
+
|
|
66
107
|
### Optional Handlebars helpers
|
|
67
108
|
|
|
68
|
-
Pass `handlebarsHelpers` on the **second** argument (alongside
|
|
109
|
+
Pass `handlebarsHelpers` on the **second** argument (alongside PDF options). Helpers apply only to that render (isolated Handlebars instance). Built-in `ifCond` is always registered.
|
|
69
110
|
|
|
70
111
|
```javascript
|
|
71
112
|
pdf.create(
|
|
@@ -113,12 +154,13 @@ You may see explicit errors such as:
|
|
|
113
154
|
</html>
|
|
114
155
|
```
|
|
115
156
|
|
|
116
|
-
## PDF options (
|
|
157
|
+
## PDF options (Puppeteer)
|
|
117
158
|
|
|
118
159
|
Examples:
|
|
119
160
|
|
|
120
|
-
- **Size:** `"height": "10.5in"`, `"width": "8in"` (units:
|
|
121
|
-
-
|
|
161
|
+
- **Size:** `"height": "10.5in"`, `"width": "8in"` (CSS units), **or** `"format": "Letter"` (A3, A4, A5, Legal, Letter, Tabloid) with `"orientation"`.
|
|
162
|
+
- **`border`:** margin around the page content (string or per-side object).
|
|
163
|
+
- **`header` / `footer`:** `contents` is HTML. In the footer, prefer **`contents.default`** for the repeating footer; `{{page}}` and `{{pages}}` work as with older versions (mapped for Chromium print).
|
|
122
164
|
|
|
123
165
|
```javascript
|
|
124
166
|
const options = {
|
|
@@ -132,11 +174,8 @@ const options = {
|
|
|
132
174
|
footer: {
|
|
133
175
|
height: "28mm",
|
|
134
176
|
contents: {
|
|
135
|
-
first: "Cover page",
|
|
136
|
-
2: "Second page",
|
|
137
177
|
default:
|
|
138
178
|
'<span style="color: #444;">{{page}}</span>/<span>{{pages}}</span>',
|
|
139
|
-
last: "Last Page",
|
|
140
179
|
},
|
|
141
180
|
},
|
|
142
181
|
};
|