Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Font Family CSS not working with Puppeteer #33

Closed
d1videbyzero opened this issue Jan 7, 2023 · 10 comments
Closed

[BUG] Font Family CSS not working with Puppeteer #33

d1videbyzero opened this issue Jan 7, 2023 · 10 comments
Labels
bug Something isn't working

Comments

@d1videbyzero
Copy link

Environment

  • chromium Version: 109.0.1
  • puppeteer / puppeteer-core Version: 19.4.1
  • Node.js Version: 16.x
  • Lambda / GCF Runtime: nodejs16.x

Description

I am using this chromium package along with puppeteer-core to generate PDFs from HTML on lambda with the serverless framework. I am using a couple different CSS fonts based on user input (Times New Roman, Calibri, Monospace, etc) but I am not getting any change in the PDF when I change the font-family value in the CSS for my HTML (all other CSS works). It should be noted that this works perfectly fine when I am running it on my own local machine.

I did notice the Fonts section of the readme for this repo, but I dont want to download any custom fonts, I just want the default CSS fonts which I mentioned above. Am I missing something? If anyone could help me out I would really appreciate it. Thank you.

@d1videbyzero d1videbyzero added the bug Something isn't working label Jan 7, 2023
@Sparticuz
Copy link
Owner

Lambda is so stripped down that it doesn't include all the base web fonts. Personally I've never added any custom fonts so I'm not even sure the code for that still works. If you want to test it out and report back that would be helpful. See this for more info https://medium.com/creditorwatch/aws-lambda-fonts-libfontconfig-5e837281a4ce

@jznadams
Copy link

jznadams commented Jan 7, 2023

I'm loading custom fonts via a lambda layer in my app using the instructions from the readme. Works great!

@d1videbyzero
Copy link
Author

@Sparticuz thank you for the info. I have just tried with lambda layers as per @jznadams suggestion, but it doesnt seem to be working. @jznadams How are you referencing your fonts? I followed the instructions in the readme and have attached my lambda layer to my function, but when I use the CSS font-family: Roboto for example, nothing changes. Are you using the fonts with CSS to generate PDFs like me or something else?

@jznadams
Copy link

jznadams commented Jan 7, 2023

  1. I'm also using Google fonts, specifically Source Sans Pro and Noto Color Emoji. I downloaded the ttf files from Google and then followed the instructions in the readme to create a zip file making sure to use the exact name .fonts.zip. I uploaded the zip file through the lambda console to create a new layer myFonts.

  2. I'm using a SAM template, so I reference the layer name and version in my function definition like this:

Resources:
  myLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Layers:
        - arn:aws:lambda:us-east-1:XXXXXXXX:layer:myFonts:1
  1. In my case, I'm downloading the HTML to render from my main web application and putting it into the /tmp directory locally from my lambda js code. I've embedded all of the CSS into the HTML itself so I don't have to do any additional network transactions for the styles.

  2. In the CSS, I just reference the fonts like this:

html,
body {
  font-family: "Source Sans Pro", sans-serif, "Noto Color Emoji";
}
  1. I generate a PDF from the HTML using puppeteer with await page.pdf and it works like a charm!

Note that if you are trying to render any emoji at all you then you will have to explicitly provide an emoji font of some kind because that's entirely missing from the base lambda. Noto Color Emoji works fine for that.

@d1videbyzero
Copy link
Author

@jznadams Thank you for the detailed explanation! Turns out I did create the lambda layer correctly but I wasn't looking close enough and my fonts are actually changing (The fonts I chose are relatively similar). So in the end, the lambda layer instructions in the README do work correctly. I appreciate the help from both of you and @Sparticuz for creating this package. Thanks!

@chrismcg
Copy link

As another data point / way to do it for people who find this via search. I have the following in my lambda Dockerfile:

FROM public.ecr.aws/lambda/nodejs:18-x86_64

RUN yum install -y google-noto-sans* google-noto-emoji*

# ...

This wasn't working until I explicitly set the FONTCONFIG_PATH environment variable so this library didn't override it.

  process.env.FONTCONFIG_PATH = '/etc/fonts';
  chromium = require('@sparticuz/chromium');

Then my html and saved PDF had the correct fonts.

@xjtroddy
Copy link

xjtroddy commented Mar 9, 2023

  1. I'm also using Google fonts, specifically Source Sans Pro and Noto Color Emoji. I downloaded the ttf files from Google and then followed the instructions in the readme to create a zip file making sure to use the exact name .fonts.zip. I uploaded the zip file through the lambda console to create a new layer myFonts.
  2. I'm using a SAM template, so I reference the layer name and version in my function definition like this:
Resources:
  myLambdaFunction:
    Type: AWS::Serverless::Function
    Properties:
      ...
      Layers:
        - arn:aws:lambda:us-east-1:XXXXXXXX:layer:myFonts:1
  1. In my case, I'm downloading the HTML to render from my main web application and putting it into the /tmp directory locally from my lambda js code. I've embedded all of the CSS into the HTML itself so I don't have to do any additional network transactions for the styles.
  2. In the CSS, I just reference the fonts like this:
html,
body {
  font-family: "Source Sans Pro", sans-serif, "Noto Color Emoji";
}
  1. I generate a PDF from the HTML using puppeteer with await page.pdf and it works like a charm!

Note that if you are trying to render any emoji at all you then you will have to explicitly provide an emoji font of some kind because that's entirely missing from the base lambda. Noto Color Emoji works fine for that.

@jznadams Thanks for your explaination, I've tried it as well, but the fonts still can not work. Is it needed to add await chromium.fonts(xxx) in the code?

@jznadams
Copy link

jznadams commented Mar 9, 2023

@jznadams Thanks for your explaination, I've tried it as well, but the fonts still can not work. Is it needed to add await chromium.fonts(xxx) in the code?

@xjtroddy No await is necessary. Double check these things:

  • The structure inside your zip file must match the readme with the font files inside a .fonts directory.
  • If you look at your lambda function through the AWS console, the layer with your fonts should be listed in the "Layers" card in the code tab. That reference is versioned, so if you have more than one version of the layer uploaded as you are testing make sure it's pointing to the right one.

@darajava
Copy link

A pretty simple way I found if using Google Fonts or similar:

Load fonts in head:

const customHTML = `
<html>
  <head>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;700&display=swap" rel="stylesheet">
  </head>
  <body>
    // ...
  </body>
</html>`;

And then wait for the content to be loaded:

await page.setContent(customHTML, {
  waitUntil: "networkidle0",
});

@Sparticuz
Copy link
Owner

Looks like this might have been addressed by the Puppeteer team puppeteer/puppeteer#12175

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants