Open JuanM04 opened 4 years ago
if you do:
pdf.create(html, {
phantomPath: path.resolve(
process.cwd(),
"node_modules/phantomjs-prebuilt/bin/phantomjs"
),
})
it works?
I already did that... It's in the first codeblock of the issue
yeah, I know. I'm asking if that worked for you.
I forgot to mention it, but I found a (hacky) solution:
First, you add a fonts.conf
wherever you have your fonts (remember to change the dir
):
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/var/task/my-font-directory/</dir>
<cachedir>/tmp/fonts-cache/</cachedir>
<config></config>
</fontconfig>
Then, you download these libs (the same from here, but in a ZIP) and put them in a folder. I put them in /bins
.
Finally, before you run pdf.create()
, set these env vars:
process.env.FONTCONFIG_PATH = path.join(process.cwd(), "my-font-directory");
process.env.LD_LIBRARY_PATH = path.join(process.cwd(), "bins");
Also, remember to change the phantomPath
!!!
pdf.create(html, {
phantomPath: path.resolve(
process.cwd(),
"node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs"
),
})
Thanks for the details! I just tried it and still didn't work 😢
Btw, how are you creating the PDF? toStream
, toBuffer
or toFile
?
I'm using toBuffer
. Could you share the error?
Same :(
wn /var/task/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs ENOENT
at Process.ChildProcess._handle.onexit (internal/child_process.js:267:19)
at onErrorNT (internal/child_process.js:469:16)
at processTicksAndRejections (internal/process/task_queues.js:84:21)
events.js:292
throw er; // Unhandled 'error' event
^
Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed
at doWrite (_stream_writable.js:399:19)
at writeOrBuffer (_stream_writable.js:387:5)
at Socket.Writable.write (_stream_writable.js:318:11)
at Socket.ondata (_stream_readable.js:717:22)
at Socket.emit (events.js:315:20)
at addChunk (_stream_readable.js:295:12)
at readableAddChunk (_stream_readable.js:271:9)
at Socket.Readable.push (_stream_readable.js:212:10)
at Pipe.onStreamRead (internal/stream_base_commons.js:186:23)
Emitted 'error' event on Socket instance at:
at errorOrDestroy (internal/streams/destroy.js:108:12)
at Socket.onerror (_stream_readable.js:753:7)
at Socket.emit (events.js:315:20)
at errorOrDestroy (internal/streams/destroy.js:108:12)
at onwriteError (_stream_writable.js:418:5)
at onwrite (_stream_writable.js:445:5)
at doWrite (_stream_writable.js:399:11)
at writeOrBuffer (_stream_writable.js:387:5)
at Socket.Writable.write (_stream_writable.js:318:11)
at Socket.ondata (_stream_readable.js:717:22) {
code: 'ERR_STREAM_DESTROYED'
}
at ChildProcess.respond (/var/task/node_modules/html-pdf/lib/pdf.js:121:31)
at ChildProcess.emit (events.js:315:20)
at Process.ChildProcess._handle.onexit (internal/child_process.js:275:12)
I'm doing:
process.env.LD_LIBRARY_PATH = path.join(process.cwd(), 'bins')
process.env.FONTCONFIG_PATH = path.join(process.cwd(), 'fonts')
pdf
.create(html, {
phantomPath: path.resolve(
process.cwd(),
'node_modules/phantomjs-prebuilt/bin/phantomjs'
),
})
.toBuffer(...)
and I have all the so files in my root /bins
, same with fonts in /fonts
and my /fonts/fonts.conf
looks like:
<?xml version="1.0"?>
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
<fontconfig>
<dir>/var/task/fonts/</dir>
<cachedir>/tmp/fonts-cache/</cachedir>
<config></config>
</fontconfig>
Oh, wait. I think I was wrong about the phantomPath
.
Try this: node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
(sorry for no answering sooner, my PC crashed)
It works 💪 😄 Thanks!
Perfect! I edited the comment for new people. Now it should be right
H @JuanM04 i know this is closed, im using this library in a Nextjs app, im rendering a certificate in pdf, locally it works just fine, but when deployed in vercel is giving me the following error:
2020-10-05T22:05:45.416Z a88c28c9-9c68-451d-9255-1e49d7ebb1cd ERROR Unhandled error during request: Error: write EPIPE
at afterWriteDispatched (internal/stream_base_commons.js:154:25)
at writeGeneric (internal/stream_base_commons.js:145:3)
at Socket._writeGeneric (net.js:786:11)
at Socket._write (net.js:798:8)
at doWrite (_stream_writable.js:403:12)
at writeOrBuffer (_stream_writable.js:387:5)
at Socket.Writable.write (_stream_writable.js:318:11)
at PDF.PdfExec [as exec] (/var/task/node_modules/html-pdf/lib/pdf.js:141:15)
at PDF.PdfToBuffer [as toBuffer] (/var/task/node_modules/html-pdf/lib/pdf.js:44:8)
at /var/task/.next/serverless/pages/pdf/[token].js:414:70 {
errno: 'EPIPE',
code: 'EPIPE',
syscall: 'write'
}
i did everything you mentioned to fix the problem with phantomjs, this is what i did
const componentToPDFBuffer = (component) => {
return new Promise((resolve, reject) => {
const html = renderToStaticMarkup(component);
const path = require('path');
process.env.FONTCONFIG_PATH = path.join(process.cwd(), "fonts");
process.env.LD_LIBRARY_PATH = path.join(process.cwd(), "bins");
const options = {
format: 'A4',
orientation: 'landscape',
type: 'pdf',
phantomPath: path.resolve(
process.cwd(),
'node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs'
),
timeout: 30000,
};
pdf.create(html, options).toBuffer((err, buffer) => {
if (err) {
return reject(err);
}
return resolve(buffer);
});
});
}
I dont know if you have faced this issue with the same library. Thnks if you can help
Are you trying to use it in the client?
Is being render on the server side using Next, this is the code that displays the pdf.
export const getServerSideProps = async (context) => {
const { res, query } = context;
const token = query.token;
const response = await fetch(`${process.env.BC_HOST}/${token}`);
const data = await response.json();
if (token !== "" && !data.status_code) {
const buffer = await pdfHelper.componentToPDFBuffer(
<PDFLayout lang={query.lang} token={token}>
{query.style === "modern" ? <ModernCertificate data={{
...data,
token: token,
lang: query.lang || "en",
strings: strings[query.lang || "en"]
}}
/> : <DefaultCertificate data={{
...data,
token: token,
lang: query.lang || "en",
strings: strings[query.lang || "en"]
}}
/>}
</PDFLayout>
);
// with this header,the browser will open the pdf directly
res.setHeader('Content-Type', 'application/pdf');
// output the pdf buffer. once res.end is triggered, it won't trigger the render method
res.end(buffer);
}
return {
props: {
data: data
}
};
}
Hmm... I don't know why it doesn't work, but try generating the PDF inside pages/api
Thanks ill try it, another thing fonts
folder its only suppose to have the content you suggest or other files?
Is the same as the .local/share/fonts
folder. You can have anything in it, but you should only have fonts
Thank you, ill try it.
@Omonroy36 Did you succeed?
@Omonroy36 Did you succeed?
I did yes
@Omonroy36 Have you had any luck using a stream? I'm really stuck here, also the fonts I'm using are all base64 in css.
I ended up using puppeteer-- was really straight forward.
let puppeteer;
if (process.env.AWS_LAMBDA_FUNCTION_VERSION) {
// running on the Vercel platform.
chrome = require('chrome-aws-lambda');
puppeteer = require('puppeteer-core');
} else {
// running locally.
puppeteer = require('puppeteer');
}
const handler = async (req, res) => {
// https://github.com/vercel/vercel/discussions/4903#discussioncomment-234166
const browser = await puppeteer.launch({
args: [...chrome.args, '--hide-scrollbars', '--disable-web-security'],
defaultViewport: chrome.defaultViewport,
executablePath: await chrome.executablePath,
headless: true,
ignoreHTTPSErrors: true,
});
const page = await browser.newPage();
await page.goto('https://www.example.com');
const pdf = await page.pdf({
format: 'A4',
orientation: 'portrait',
margin: {
top: "10mm",
right: "10mm",
bottom: "10mm",
left: "10mm",
},
timeout: 30000,
})
await browser.close();
res.setHeader('Content-disposition', `attachment; filename="test.pdf`)
res.setHeader('Content-Type', 'application/pdf')
res.end(pdf)
}
export default handler
Borrowed a little from here https://github.com/vercel/vercel/discussions/4903#discussioncomment-234166
Hi,
I'm still getting the below error:
{
"errorType": "Error",
"errorMessage": "write EPIPE",
"code": "EPIPE",
"errno": -32,
"syscall": "write",
"stack": [
"Error: write EPIPE",
" at afterWriteDispatched (internal/stream_base_commons.js:156:25)",
" at writeGeneric (internal/stream_base_commons.js:147:3)",
" at Socket._writeGeneric (net.js:798:11)",
" at Socket._write (net.js:810:8)",
" at writeOrBuffer (internal/streams/writable.js:358:12)",
" at Socket.Writable.write (internal/streams/writable.js:303:10)",
" at PDF.PdfExec [as exec] (/var/task/node_modules/html-pdf/lib/pdf.js:156:15)",
" at PDF.PdfToBuffer [as toBuffer] (/var/task/node_modules/html-pdf/lib/pdf.js:46:8)",
" at /var/task/node_modules/@yorck/booking-client/dist/booking.js:214:42",
" at new Promise (<anonymous>)"
]
}
See below the phantom path and ENV vars. Please note I'm using my own npm package where I have the PDF generation code, as I need to reuse it across several repos.
phantomPath= /var/task/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
FONTCONFIG_PATH: '/var/task/node_modules/@yorck/booking-client/fonts'
LD_LIBRARY_PATH: '/var/task/node_modules/@yorck/booking-client/bin'
I'm deploying it to AWS Lambda (Node.js 14.x) through the serverless framework.
This error is driving me crazy, I've been stuck with it for a while!
Thanks!
@cgonzalezsan I'm having the same issue when using serverless-plugin-include-dependencies and serverless-plugin-common-excludes they both have the effect to remove phantomjs-prebuilt
you can try
option1: remove serverless-plugin-include-dependencies and serverless-plugin-common-excludes from serverless.yml
option2: add
package:
patterns:
- node_modules/html-pdf/**
- node_modules/phantomjs-prebuilt/**
this will force add html-pdf and phantomjs-prebuilt in artifact bundle (this works in my simple setup lambda but doesn't work for lambda with lots of dependencies somehow)
option3: only remove serverless-plugin-common-excludes from serverless.yml
option4:
option 4 gives me the optimized bundle size and makes sure html-pdf and phantomjs-prebuilt included in artifact bundle
Hi,
I'm still getting the below error:
{ "errorType": "Error", "errorMessage": "write EPIPE", "code": "EPIPE", "errno": -32, "syscall": "write", "stack": [ "Error: write EPIPE", " at afterWriteDispatched (internal/stream_base_commons.js:156:25)", " at writeGeneric (internal/stream_base_commons.js:147:3)", " at Socket._writeGeneric (net.js:798:11)", " at Socket._write (net.js:810:8)", " at writeOrBuffer (internal/streams/writable.js:358:12)", " at Socket.Writable.write (internal/streams/writable.js:303:10)", " at PDF.PdfExec [as exec] (/var/task/node_modules/html-pdf/lib/pdf.js:156:15)", " at PDF.PdfToBuffer [as toBuffer] (/var/task/node_modules/html-pdf/lib/pdf.js:46:8)", " at /var/task/node_modules/@yorck/booking-client/dist/booking.js:214:42", " at new Promise (<anonymous>)" ] }
See below the phantom path and ENV vars. Please note I'm using my own npm package where I have the PDF generation code, as I need to reuse it across several repos.
phantomPath= /var/task/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs FONTCONFIG_PATH: '/var/task/node_modules/@yorck/booking-client/fonts' LD_LIBRARY_PATH: '/var/task/node_modules/@yorck/booking-client/bin'
I'm deploying it to AWS Lambda (Node.js 14.x) through the serverless framework.
This error is driving me crazy, I've been stuck with it for a while!
Thanks!
Hey, Any update on this I'm getting the same for the 12 and 14 node versions on AWS-lambda.
I forgot to mention it, but I found a (hacky) solution:
First, you add a
fonts.conf
wherever you have your fonts (remember to change thedir
):
Hey bro. Where i could find the fonts.conf file?
I forgot to mention it, but I found a (hacky) solution: First, you add a
fonts.conf
wherever you have your fonts (remember to change thedir
):Hey bro. Where i could find the fonts.conf file?
https://github.com/naeemshaikh27/phantom-lambda-fontconfig-pack
Following solved it for me on Vercel with node v18, and latest puppeteer-core. Credits stefanjudis.
Somewhere in your helpers.js
const chromium = require('@sparticuz/chromium-min');
const puppeteer = require('puppeteer-core');
let _page;
exports.getBrowser = async function () {
return puppeteer.launch({
args: [...chromium.args, '--hide-scrollbars', '--disable-web-security'],
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath(
`https://github.com/Sparticuz/chromium/releases/download/v119.0.2/chromium-v119.0.2-pack.tar`
),
headless: chromium.headless,
ignoreHTTPSErrors: true,
});
}
exports.getPage = async function getPage() {
if (_page) return _page;
const browser = await module.exports.getBrowser();
_page = await browser.newPage();
return _page;
}
Using it like so:
const page = await getPage();
await page.emulateMediaType('screen'); // To reflect CSS used for screens instead of print
const pdf = await page.pdf({
format: info.format || 'A4',
orientation: 'portrait',
timeout: 30000,
})
In my PC (Kubuntu 20.04) it works perfectly. The problem appears when I deploy to Vercel. To begin with, I need to set
phantomPath
, otherwise I get a "write EPIPE" error:Now, if I run it, it throws: