@maistik/nuxt-pdf 1.0.17 → 1.1.4
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/LICENSE +21 -0
- package/README.md +427 -186
- package/dist/module.d.mts +2 -2
- package/dist/module.d.ts +2 -2
- package/dist/module.json +4 -4
- package/dist/module.mjs +20 -8
- package/dist/runtime/composables/usePdf.d.ts +2 -2
- package/dist/runtime/server/api/pdf.post.js +38 -12
- package/dist/runtime/types.d.ts +3 -3
- package/dist/runtime/utils/compiler.d.ts +4 -3
- package/dist/runtime/utils/compiler.js +48 -39
- package/dist/runtime/utils/providers.d.ts +2 -2
- package/dist/runtime/utils/providers.js +46 -10
- package/package.json +33 -31
package/dist/module.d.mts
CHANGED
|
@@ -7,7 +7,7 @@ interface PdfModuleOptions {
|
|
|
7
7
|
enableI18n: boolean;
|
|
8
8
|
defaultLocale: string;
|
|
9
9
|
availableLocales: string[];
|
|
10
|
-
i18nMessages: Record<string, Record<string,
|
|
10
|
+
i18nMessages: Record<string, Record<string, unknown>>;
|
|
11
11
|
providers: {
|
|
12
12
|
gotenberg: {
|
|
13
13
|
url: string;
|
|
@@ -17,7 +17,7 @@ interface PdfModuleOptions {
|
|
|
17
17
|
apiKey: string;
|
|
18
18
|
};
|
|
19
19
|
puppeteer: {
|
|
20
|
-
launchOptions: Record<string,
|
|
20
|
+
launchOptions: Record<string, unknown>;
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
defaultOptions: {
|
package/dist/module.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ interface PdfModuleOptions {
|
|
|
7
7
|
enableI18n: boolean;
|
|
8
8
|
defaultLocale: string;
|
|
9
9
|
availableLocales: string[];
|
|
10
|
-
i18nMessages: Record<string, Record<string,
|
|
10
|
+
i18nMessages: Record<string, Record<string, unknown>>;
|
|
11
11
|
providers: {
|
|
12
12
|
gotenberg: {
|
|
13
13
|
url: string;
|
|
@@ -17,7 +17,7 @@ interface PdfModuleOptions {
|
|
|
17
17
|
apiKey: string;
|
|
18
18
|
};
|
|
19
19
|
puppeteer: {
|
|
20
|
-
launchOptions: Record<string,
|
|
20
|
+
launchOptions: Record<string, unknown>;
|
|
21
21
|
};
|
|
22
22
|
};
|
|
23
23
|
defaultOptions: {
|
package/dist/module.json
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"name": "@maistik/nuxt-pdf",
|
|
3
3
|
"configKey": "pdf",
|
|
4
4
|
"compatibility": {
|
|
5
|
-
"nuxt": "
|
|
5
|
+
"nuxt": ">=3.0.0"
|
|
6
6
|
},
|
|
7
|
-
"version": "1.
|
|
7
|
+
"version": "1.1.4",
|
|
8
8
|
"builder": {
|
|
9
|
-
"@nuxt/module-builder": "1.0.
|
|
10
|
-
"unbuild": "3.
|
|
9
|
+
"@nuxt/module-builder": "1.0.2",
|
|
10
|
+
"unbuild": "3.6.1"
|
|
11
11
|
}
|
|
12
12
|
}
|
package/dist/module.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, addServerHandler, addImports } from '@nuxt/kit';
|
|
1
|
+
import { defineNuxtModule, createResolver, addServerTemplate, addServerHandler, addImports } from '@nuxt/kit';
|
|
2
2
|
import { existsSync, readdirSync, statSync, readFileSync } from 'fs';
|
|
3
3
|
import { join } from 'path';
|
|
4
4
|
|
|
5
|
-
const module = defineNuxtModule({
|
|
5
|
+
const module$1 = defineNuxtModule({
|
|
6
6
|
meta: {
|
|
7
7
|
name: "@maistik/nuxt-pdf",
|
|
8
8
|
configKey: "pdf",
|
|
9
9
|
compatibility: {
|
|
10
|
-
nuxt: "
|
|
10
|
+
nuxt: ">=3.0.0"
|
|
11
11
|
}
|
|
12
12
|
},
|
|
13
13
|
defaults: {
|
|
@@ -55,14 +55,15 @@ const module = defineNuxtModule({
|
|
|
55
55
|
const resolver = createResolver(import.meta.url);
|
|
56
56
|
const templateSources = {};
|
|
57
57
|
const partialSources = {};
|
|
58
|
+
const baseDir = nuxt.options.rootDir;
|
|
58
59
|
for (const componentDir of options.components) {
|
|
59
|
-
const fullPath = join(
|
|
60
|
+
const fullPath = join(baseDir, componentDir);
|
|
60
61
|
if (existsSync(fullPath)) {
|
|
61
62
|
scanDirectory(fullPath, templateSources, ".hbs");
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
for (const sharedDir of options.sharedComponents) {
|
|
65
|
-
const fullPath = join(
|
|
66
|
+
const fullPath = join(baseDir, sharedDir);
|
|
66
67
|
if (existsSync(fullPath)) {
|
|
67
68
|
scanDirectory(fullPath, partialSources, ".hbs");
|
|
68
69
|
}
|
|
@@ -76,9 +77,12 @@ const module = defineNuxtModule({
|
|
|
76
77
|
providers: options.providers,
|
|
77
78
|
defaultOptions: options.defaultOptions,
|
|
78
79
|
templateSources,
|
|
79
|
-
partialSources
|
|
80
|
-
customHelpers: options.customHelpers || {}
|
|
80
|
+
partialSources
|
|
81
81
|
};
|
|
82
|
+
addServerTemplate({
|
|
83
|
+
filename: "#pdf-custom-helpers",
|
|
84
|
+
getContents: () => generateCustomHelpersModule(options.customHelpers || {})
|
|
85
|
+
});
|
|
82
86
|
nuxt.options.runtimeConfig.public.pdf = {
|
|
83
87
|
enableI18n: options.enableI18n,
|
|
84
88
|
defaultLocale: options.defaultLocale,
|
|
@@ -86,6 +90,7 @@ const module = defineNuxtModule({
|
|
|
86
90
|
};
|
|
87
91
|
addServerHandler({
|
|
88
92
|
route: "/api/pdf",
|
|
93
|
+
method: "post",
|
|
89
94
|
handler: resolver.resolve("./runtime/server/api/pdf.post")
|
|
90
95
|
});
|
|
91
96
|
addImports({
|
|
@@ -95,6 +100,13 @@ const module = defineNuxtModule({
|
|
|
95
100
|
});
|
|
96
101
|
}
|
|
97
102
|
});
|
|
103
|
+
function generateCustomHelpersModule(helpers) {
|
|
104
|
+
const entries = Object.entries(helpers).filter(([, fn]) => typeof fn === "function").map(([name, fn]) => ` ${JSON.stringify(name)}: ${fn.toString()}`);
|
|
105
|
+
return `export const customHelpers = {
|
|
106
|
+
${entries.join(",\n")}
|
|
107
|
+
}
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
98
110
|
function scanDirectory(dir, sources, extension) {
|
|
99
111
|
if (!existsSync(dir)) return;
|
|
100
112
|
const files = readdirSync(dir);
|
|
@@ -110,4 +122,4 @@ function scanDirectory(dir, sources, extension) {
|
|
|
110
122
|
}
|
|
111
123
|
}
|
|
112
124
|
|
|
113
|
-
export { module as default };
|
|
125
|
+
export { module$1 as default };
|
|
@@ -15,8 +15,8 @@ export interface PdfGenerateOptions {
|
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
export declare function usePdf(): {
|
|
18
|
-
generate: (template: string, data:
|
|
19
|
-
download: (template: string, data:
|
|
18
|
+
generate: (template: string, data: Record<string, unknown>, options?: PdfGenerateOptions, locale?: string) => Promise<Blob>;
|
|
19
|
+
download: (template: string, data: Record<string, unknown>, options?: PdfGenerateOptions, filename?: string, locale?: string) => Promise<void>;
|
|
20
20
|
getAvailableLocales: () => string[];
|
|
21
21
|
getDefaultLocale: () => string;
|
|
22
22
|
};
|
|
@@ -1,23 +1,43 @@
|
|
|
1
|
-
import { defineEventHandler, readBody, setHeader } from "h3";
|
|
1
|
+
import { defineEventHandler, readBody, setHeader, createError, isError } from "h3";
|
|
2
2
|
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { customHelpers } from "#pdf-custom-helpers";
|
|
3
4
|
import { compilePdfComponent } from "../../utils/compiler.js";
|
|
4
5
|
import { createPdfProvider } from "../../utils/providers.js";
|
|
5
6
|
export default defineEventHandler(async (event) => {
|
|
7
|
+
const config = useRuntimeConfig();
|
|
8
|
+
const body = await readBody(event);
|
|
9
|
+
const template = body?.template;
|
|
10
|
+
const ctx = body?.ctx;
|
|
11
|
+
if (typeof template !== "string" || template.length === 0) {
|
|
12
|
+
throw createError({
|
|
13
|
+
statusCode: 400,
|
|
14
|
+
statusMessage: 'Missing or invalid "template"'
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
if (!ctx || typeof ctx !== "object") {
|
|
18
|
+
throw createError({
|
|
19
|
+
statusCode: 400,
|
|
20
|
+
statusMessage: 'Missing or invalid "ctx"'
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const templateSources = config.pdf.templateSources;
|
|
24
|
+
if (!Object.prototype.hasOwnProperty.call(templateSources, template)) {
|
|
25
|
+
throw createError({
|
|
26
|
+
statusCode: 404,
|
|
27
|
+
statusMessage: `Template "${template}" not found`
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
const { data, options = {}, locale } = ctx;
|
|
31
|
+
const mergedOptions = { ...config.pdf.defaultOptions, ...options };
|
|
32
|
+
const messages = config.pdf.enableI18n ? config.pdf.i18nMessages[locale || config.pdf.defaultLocale] || {} : {};
|
|
6
33
|
try {
|
|
7
|
-
const config = useRuntimeConfig();
|
|
8
|
-
const { template, ctx } = await readBody(event);
|
|
9
|
-
if (!template || !ctx) {
|
|
10
|
-
throw new Error("Missing template or context");
|
|
11
|
-
}
|
|
12
|
-
const { data, options = {}, locale } = ctx;
|
|
13
|
-
const mergedOptions = { ...config.pdf.defaultOptions, ...options };
|
|
14
|
-
const messages = config.pdf.enableI18n ? config.pdf.i18nMessages[locale || config.pdf.defaultLocale] || {} : {};
|
|
15
34
|
const html = compilePdfComponent(
|
|
16
35
|
template,
|
|
17
36
|
{ data, options: mergedOptions, locale },
|
|
18
37
|
messages,
|
|
19
|
-
|
|
20
|
-
config.pdf.partialSources
|
|
38
|
+
templateSources,
|
|
39
|
+
config.pdf.partialSources,
|
|
40
|
+
customHelpers
|
|
21
41
|
);
|
|
22
42
|
const provider = createPdfProvider(config.pdf.provider, config.pdf.providers);
|
|
23
43
|
const pdfBuffer = await provider.generatePdf(html, mergedOptions);
|
|
@@ -26,6 +46,12 @@ export default defineEventHandler(async (event) => {
|
|
|
26
46
|
return pdfBuffer;
|
|
27
47
|
} catch (error) {
|
|
28
48
|
console.error("PDF generation error:", error);
|
|
29
|
-
|
|
49
|
+
if (isError(error)) {
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
throw createError({
|
|
53
|
+
statusCode: 500,
|
|
54
|
+
statusMessage: "Failed to generate PDF"
|
|
55
|
+
});
|
|
30
56
|
}
|
|
31
57
|
});
|
package/dist/runtime/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export interface PdfContext {
|
|
2
|
-
data:
|
|
2
|
+
data: Record<string, unknown>;
|
|
3
3
|
options: PdfOptions;
|
|
4
4
|
locale?: string;
|
|
5
5
|
}
|
|
@@ -28,9 +28,9 @@ export interface PdfProviderConfig {
|
|
|
28
28
|
apiKey: string;
|
|
29
29
|
};
|
|
30
30
|
puppeteer: {
|
|
31
|
-
launchOptions: Record<string,
|
|
31
|
+
launchOptions: Record<string, unknown>;
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
export interface PdfProvider {
|
|
35
|
-
generatePdf(html: string, options:
|
|
35
|
+
generatePdf(html: string, options: PdfOptions): Promise<Buffer>;
|
|
36
36
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import type { HelperDelegate } from 'handlebars';
|
|
1
2
|
export declare function compilePdfComponent(templateName: string, ctx: {
|
|
2
|
-
data:
|
|
3
|
-
options:
|
|
3
|
+
data: Record<string, unknown>;
|
|
4
|
+
options: Record<string, unknown>;
|
|
4
5
|
locale?: string;
|
|
5
|
-
}, messages: Record<string, string>, templateSources: Record<string, string>, partialSources: Record<string, string>): string;
|
|
6
|
+
}, messages: Record<string, string>, templateSources: Record<string, string>, partialSources: Record<string, string>, customHelpers?: Record<string, HelperDelegate>): string;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { useRuntimeConfig } from "#imports";
|
|
2
1
|
import Handlebars from "handlebars";
|
|
3
|
-
export function compilePdfComponent(templateName, ctx, messages, templateSources, partialSources) {
|
|
2
|
+
export function compilePdfComponent(templateName, ctx, messages, templateSources, partialSources, customHelpers = {}) {
|
|
4
3
|
const handlebars = Handlebars.create();
|
|
5
4
|
handlebars.registerHelper("t", function(key) {
|
|
6
5
|
const keys = key.split(".");
|
|
7
6
|
let value = messages;
|
|
8
7
|
for (const k of keys) {
|
|
9
|
-
if (value && typeof value === "object" && k
|
|
8
|
+
if (value && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, k)) {
|
|
10
9
|
value = value[k];
|
|
11
10
|
} else {
|
|
12
11
|
return key;
|
|
@@ -21,8 +20,11 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
|
|
|
21
20
|
let currency = "USD";
|
|
22
21
|
if (typeof currencyOrOptions === "string") {
|
|
23
22
|
currency = currencyOrOptions;
|
|
24
|
-
} else
|
|
25
|
-
|
|
23
|
+
} else {
|
|
24
|
+
const hash = currencyOrOptions?.hash;
|
|
25
|
+
if (typeof hash?.currency === "string") {
|
|
26
|
+
currency = hash.currency;
|
|
27
|
+
}
|
|
26
28
|
}
|
|
27
29
|
if (!/^[A-Z]{3}$/.test(currency)) {
|
|
28
30
|
currency = "USD";
|
|
@@ -42,20 +44,29 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
|
|
|
42
44
|
}
|
|
43
45
|
return isEqual;
|
|
44
46
|
});
|
|
45
|
-
handlebars.registerHelper(
|
|
46
|
-
|
|
47
|
-
(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
)
|
|
47
|
+
handlebars.registerHelper("ne", function(a, b, options) {
|
|
48
|
+
const result = a !== b;
|
|
49
|
+
if (options && typeof options.fn === "function") {
|
|
50
|
+
return result ? options.fn(this) : options.inverse(this);
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
});
|
|
54
|
+
handlebars.registerHelper("gt", function(a, b, options) {
|
|
55
|
+
const result = a > b;
|
|
56
|
+
if (options && typeof options.fn === "function") {
|
|
57
|
+
return result ? options.fn(this) : options.inverse(this);
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
});
|
|
53
61
|
handlebars.registerHelper("formatDate", function(date, formatOrOptions) {
|
|
54
62
|
let style = "short";
|
|
55
63
|
if (typeof formatOrOptions === "string") {
|
|
56
64
|
style = formatOrOptions;
|
|
57
|
-
} else
|
|
58
|
-
|
|
65
|
+
} else {
|
|
66
|
+
const hash = formatOrOptions?.hash;
|
|
67
|
+
if (typeof hash?.format === "string") {
|
|
68
|
+
style = hash.format;
|
|
69
|
+
}
|
|
59
70
|
}
|
|
60
71
|
if (!["full", "long", "medium", "short"].includes(style)) {
|
|
61
72
|
style = "short";
|
|
@@ -75,22 +86,17 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
|
|
|
75
86
|
dateStyle: style
|
|
76
87
|
}).format(dateObj);
|
|
77
88
|
});
|
|
78
|
-
handlebars.registerHelper("formatNumber", function(value, options
|
|
89
|
+
handlebars.registerHelper("formatNumber", function(value, options) {
|
|
79
90
|
if (typeof value !== "number") return value;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
handlebars.registerHelper(name, helper);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
+
const intlOptions = options && typeof options.hash === "object" ? options.hash : {};
|
|
92
|
+
return new Intl.NumberFormat(ctx.locale || "en-US", intlOptions).format(value);
|
|
93
|
+
});
|
|
94
|
+
if (customHelpers && typeof customHelpers === "object") {
|
|
95
|
+
for (const [name, helper] of Object.entries(customHelpers)) {
|
|
96
|
+
if (typeof helper === "function") {
|
|
97
|
+
handlebars.registerHelper(name, helper);
|
|
98
|
+
}
|
|
91
99
|
}
|
|
92
|
-
} catch (error) {
|
|
93
|
-
console.warn("Failed to load custom helpers:", error);
|
|
94
100
|
}
|
|
95
101
|
handlebars.registerHelper("upper", function(str) {
|
|
96
102
|
return String(str || "").toUpperCase();
|
|
@@ -138,13 +144,15 @@ export function compilePdfComponent(templateName, ctx, messages, templateSources
|
|
|
138
144
|
function enrichContextForTemplate(templateName, data) {
|
|
139
145
|
const enriched = { ...data };
|
|
140
146
|
if (templateName.toLowerCase().includes("invoice")) {
|
|
141
|
-
if (
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
enriched.
|
|
147
|
-
|
|
147
|
+
if (Array.isArray(enriched.items)) {
|
|
148
|
+
const items = enriched.items;
|
|
149
|
+
const subtotal = items.reduce((sum, item) => sum + item.quantity * item.price, 0);
|
|
150
|
+
const taxRate = typeof enriched.taxRate === "number" ? enriched.taxRate : 0.1;
|
|
151
|
+
const tax = subtotal * taxRate;
|
|
152
|
+
enriched.subtotal = subtotal;
|
|
153
|
+
enriched.tax = tax;
|
|
154
|
+
enriched.total = subtotal + tax;
|
|
155
|
+
if (enriched.issueDate && typeof enriched.paymentTerms === "number") {
|
|
148
156
|
const issueDate = new Date(enriched.issueDate);
|
|
149
157
|
const dueDate = new Date(issueDate);
|
|
150
158
|
dueDate.setDate(dueDate.getDate() + enriched.paymentTerms);
|
|
@@ -153,9 +161,10 @@ function enrichContextForTemplate(templateName, data) {
|
|
|
153
161
|
}
|
|
154
162
|
}
|
|
155
163
|
if (templateName.toLowerCase().includes("salesreport")) {
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
-
|
|
164
|
+
if (Array.isArray(enriched.salesData)) {
|
|
165
|
+
const salesData = enriched.salesData;
|
|
166
|
+
enriched.quarters = calculateQuarters(salesData);
|
|
167
|
+
const totalSales = salesData.reduce((sum, item) => sum + item.amount, 0);
|
|
159
168
|
enriched.rating = calculatePerformanceRating(totalSales);
|
|
160
169
|
}
|
|
161
170
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { PdfProvider } from '../types.js';
|
|
2
|
-
export declare function createPdfProvider(providerType: string, config:
|
|
1
|
+
import type { PdfProvider, PdfProviderConfig } from '../types.js';
|
|
2
|
+
export declare function createPdfProvider(providerType: string, config: Partial<PdfProviderConfig>): PdfProvider;
|
|
@@ -29,10 +29,10 @@ class GotenbergProvider {
|
|
|
29
29
|
form.append("paperHeight", dimensions.height);
|
|
30
30
|
}
|
|
31
31
|
if (options.margin) {
|
|
32
|
-
form.append("marginTop", (options.margin.top / 25.4).toString());
|
|
33
|
-
form.append("marginBottom", (options.margin.bottom / 25.4).toString());
|
|
34
|
-
form.append("marginLeft", (options.margin.left / 25.4).toString());
|
|
35
|
-
form.append("marginRight", (options.margin.right / 25.4).toString());
|
|
32
|
+
form.append("marginTop", ((options.margin.top ?? 0) / 25.4).toString());
|
|
33
|
+
form.append("marginBottom", ((options.margin.bottom ?? 0) / 25.4).toString());
|
|
34
|
+
form.append("marginLeft", ((options.margin.left ?? 0) / 25.4).toString());
|
|
35
|
+
form.append("marginRight", ((options.margin.right ?? 0) / 25.4).toString());
|
|
36
36
|
}
|
|
37
37
|
if (options.landscape) {
|
|
38
38
|
form.append("landscape", "true");
|
|
@@ -97,22 +97,58 @@ class PuppeteerProvider {
|
|
|
97
97
|
constructor(config) {
|
|
98
98
|
this.config = config;
|
|
99
99
|
}
|
|
100
|
+
// Launching a full Chromium per request is slow and flaky (especially on CI),
|
|
101
|
+
// so we keep one browser alive and reuse it, relaunching if it disconnects.
|
|
102
|
+
static browser = null;
|
|
103
|
+
static launching = null;
|
|
104
|
+
async getBrowser() {
|
|
105
|
+
const existing = PuppeteerProvider.browser;
|
|
106
|
+
if (existing?.connected) {
|
|
107
|
+
return existing;
|
|
108
|
+
}
|
|
109
|
+
if (!PuppeteerProvider.launching) {
|
|
110
|
+
PuppeteerProvider.launching = (async () => {
|
|
111
|
+
const puppeteer = await import("puppeteer").then((m) => m.default);
|
|
112
|
+
const launchOptions = this.config.launchOptions;
|
|
113
|
+
const browser = await puppeteer.launch({
|
|
114
|
+
// `--disable-dev-shm-usage` avoids Chromium exhausting the small
|
|
115
|
+
// /dev/shm tmpfs in CI/Docker, a common cause of hangs and crashes.
|
|
116
|
+
...launchOptions,
|
|
117
|
+
args: ["--disable-dev-shm-usage", ...launchOptions?.args ?? []]
|
|
118
|
+
});
|
|
119
|
+
PuppeteerProvider.browser = browser;
|
|
120
|
+
browser.on("disconnected", () => {
|
|
121
|
+
PuppeteerProvider.browser = null;
|
|
122
|
+
});
|
|
123
|
+
return browser;
|
|
124
|
+
})();
|
|
125
|
+
try {
|
|
126
|
+
await PuppeteerProvider.launching;
|
|
127
|
+
} finally {
|
|
128
|
+
PuppeteerProvider.launching = null;
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
await PuppeteerProvider.launching;
|
|
132
|
+
}
|
|
133
|
+
return PuppeteerProvider.browser;
|
|
134
|
+
}
|
|
100
135
|
async generatePdf(html, options) {
|
|
101
|
-
const
|
|
102
|
-
const
|
|
136
|
+
const browser = await this.getBrowser();
|
|
137
|
+
const page = await browser.newPage();
|
|
103
138
|
try {
|
|
104
|
-
|
|
105
|
-
await page.setContent(html, { waitUntil: "networkidle0" });
|
|
139
|
+
await page.setContent(html, { waitUntil: "domcontentloaded", timeout: 3e4 });
|
|
106
140
|
const pdfOptions = {
|
|
107
141
|
format: options.format || "A4",
|
|
108
142
|
margin: options.margin,
|
|
109
143
|
landscape: options.landscape || false,
|
|
110
|
-
printBackground: options.printBackground !== false
|
|
144
|
+
printBackground: options.printBackground !== false,
|
|
145
|
+
timeout: 3e4
|
|
111
146
|
};
|
|
112
147
|
const pdfBuffer = await page.pdf(pdfOptions);
|
|
113
148
|
return Buffer.from(pdfBuffer);
|
|
114
149
|
} finally {
|
|
115
|
-
await
|
|
150
|
+
await page.close().catch(() => {
|
|
151
|
+
});
|
|
116
152
|
}
|
|
117
153
|
}
|
|
118
154
|
}
|
package/package.json
CHANGED
|
@@ -1,50 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maistik/nuxt-pdf",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "A Nuxt 3 module for server-side PDF generation using Handlebars templates",
|
|
3
|
+
"version": "1.1.4",
|
|
4
|
+
"description": "A Nuxt 3 & 4 module for server-side PDF generation using Handlebars templates",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"main": "./dist/module.mjs",
|
|
8
8
|
"files": [
|
|
9
9
|
"dist"
|
|
10
10
|
],
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"dev": "nuxi dev playground",
|
|
14
|
-
"dev:build": "nuxi build playground",
|
|
15
|
-
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
16
|
-
"release": "npm run lint && npm run test:unit && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
|
|
17
|
-
"lint": "eslint .",
|
|
18
|
-
"lint:fix": "eslint . --fix",
|
|
19
|
-
"test": "vitest run && playwright test",
|
|
20
|
-
"test:watch": "vitest watch",
|
|
21
|
-
"test:unit": "vitest run",
|
|
22
|
-
"test:e2e": "playwright test",
|
|
23
|
-
"test:e2e:ui": "playwright test --ui",
|
|
24
|
-
"prepack": "nuxt-module-build build"
|
|
11
|
+
"engines": {
|
|
12
|
+
"node": ">=22.0.0"
|
|
25
13
|
},
|
|
26
14
|
"dependencies": {
|
|
27
|
-
"@nuxt/kit": "^
|
|
28
|
-
"handlebars": "^4.7.
|
|
29
|
-
"puppeteer": "^
|
|
30
|
-
"form-data": "^4.0.
|
|
15
|
+
"@nuxt/kit": "^4.4.8",
|
|
16
|
+
"handlebars": "^4.7.9",
|
|
17
|
+
"puppeteer": "^25.1.0",
|
|
18
|
+
"form-data": "^4.0.6"
|
|
31
19
|
},
|
|
32
20
|
"devDependencies": {
|
|
33
21
|
"@nuxt/devtools": "latest",
|
|
34
|
-
"@nuxt/eslint-config": "^1.
|
|
35
|
-
"@nuxt/module-builder": "^1.0.
|
|
36
|
-
"@nuxt/schema": "^
|
|
37
|
-
"@nuxt/test-utils": "^
|
|
38
|
-
"@playwright/test": "^1.
|
|
22
|
+
"@nuxt/eslint-config": "^1.16.0",
|
|
23
|
+
"@nuxt/module-builder": "^1.0.2",
|
|
24
|
+
"@nuxt/schema": "^4.4.8",
|
|
25
|
+
"@nuxt/test-utils": "^4.0.3",
|
|
26
|
+
"@playwright/test": "^1.60.0",
|
|
39
27
|
"changelogen": "^0.6.2",
|
|
40
|
-
"eslint": "^
|
|
41
|
-
"nuxt": "^
|
|
42
|
-
"unbuild": "^3.
|
|
43
|
-
"vitest": "^
|
|
28
|
+
"eslint": "^10.5.0",
|
|
29
|
+
"nuxt": "^4.4.8",
|
|
30
|
+
"unbuild": "^3.6.1",
|
|
31
|
+
"vitest": "^4.1.8"
|
|
44
32
|
},
|
|
45
33
|
"keywords": [
|
|
46
34
|
"nuxt",
|
|
47
35
|
"nuxt3",
|
|
36
|
+
"nuxt4",
|
|
48
37
|
"pdf",
|
|
49
38
|
"handlebars",
|
|
50
39
|
"gotenberg",
|
|
@@ -57,5 +46,18 @@
|
|
|
57
46
|
"type": "git",
|
|
58
47
|
"url": "https://github.com/Maistik-Studio/nuxt-pdf"
|
|
59
48
|
},
|
|
60
|
-
"
|
|
61
|
-
|
|
49
|
+
"scripts": {
|
|
50
|
+
"build": "nuxt-module-build prepare && nuxt-module-build build",
|
|
51
|
+
"dev": "nuxi dev playground",
|
|
52
|
+
"dev:build": "nuxi build playground",
|
|
53
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
54
|
+
"release": "npm run lint && npm run test:unit && npm run prepack && changelogen --release && npm publish --access public && git push --follow-tags",
|
|
55
|
+
"lint": "eslint .",
|
|
56
|
+
"lint:fix": "eslint . --fix",
|
|
57
|
+
"test": "vitest run && playwright test",
|
|
58
|
+
"test:watch": "vitest watch",
|
|
59
|
+
"test:unit": "vitest run",
|
|
60
|
+
"test:e2e": "playwright test",
|
|
61
|
+
"test:e2e:ui": "playwright test --ui"
|
|
62
|
+
}
|
|
63
|
+
}
|