Skip to content

Instantly share code, notes, and snippets.

@nat-n
Last active February 28, 2024 19:23
Show Gist options
  • Save nat-n/c3429d29f2478ccb3de243810bb12956 to your computer and use it in GitHub Desktop.
Save nat-n/c3429d29f2478ccb3de243810bb12956 to your computer and use it in GitHub Desktop.
How to build a fontconfig bundle for adding arbitrary fonts to headless chrome independent of the OS. This is specifically useful for deploying headless chrome to AWS lambda where it is necessary to include fonts for rendering CJK (Chinese, Japanese, Korean) characters into the deployed bundle.

Building fontconfig

Start up a lambda-like docker container:

docker run -i -t -v /tmp:/var/task lambci/lambda:build /bin/bash

Install some dependencies inside the container:

yum install gperf freetype-devel libxml2-devel git libtool -y
easy_install pip
/usr/local/bin/pip install lxml

Checkout fontconfig inside the container

cd /tmp
git clone http://anongit.freedesktop.org/git/fontconfig
cd fontconfig
git checkout -b 2.12.4 refs/tags/2.12.4

Build and install fontconfig. It’s import that $FONTCONFIG_PATH is set to a path that exists in the container now (create it) and is that same as where fontconfig will live when deployed to lambda

export FONTCONFIG_PATH=/var/task/<MyLabmda>/headless-chrome/fontconfig
./autogen.sh --sysconfdir=$FONTCONFIG_PATH/etc --prefix=$FONTCONFIG_PATH/usr --mandir=$FONTCONFIG_PATH/usr/share/man --enable-libxml2
make
make install

Configuring fontconfig

You should now be able to find the built/installed fontconfig somewhere in the /tmp dir of your host OS. The next steps can be done there outside the container.

You’ll find find /tmp/…/fontconfig/etc/fonts/conf.d contains a bunch of symlinks to files in /tmp/…/fontconfig/usr/share/fontconfig/conf.avail. Trying to deploy a bundle with symlinks will fail, so you need to replace the symlinks with copies of the linked files.

Next we need to configure our fontconfig to load it’s own fonts (in addition to system fonts). The most reliable way to do this is to add a <dir> entry to Font directory list section of /tmp/…/fontconfig/etc/fonts/fonts.conf like <dir>/var/task/<MyLambda>/headless-chrome/fontconfig/usr/share/fonts</dir>. Again it’s crucial that this path points to what will be the correct location inside your deployed lambda. There are some warnings about not editing this file but that probably doesn’t matter for us.

Installing and caching fonts

Next step is to install the font(s) we want to support, by placing them in /tmp/…/fontconfig/usr/share/fonts (the directory referenced by fonts.conf in the previous step).

Finally and crucially we need to cache the newly installed fonts. This is done back in the container where we built fontconfig. Firstly to ensure setup the environment so that fontconfig will work in out session run:

export LD_LIBRARY_PATH=/var/task/<MyLambda>/headless-chrome/fontconfig/usr/lib
export FONTCONFIG_PATH=/var/task/<MyLambda>/headless-chrome/fontconfig/etc/fonts

Then to cache the newly installed fonts run:

/var/task/<MyLambda>/headless-chrome/fontconfig/usr/bin/fc-cache -svf

This should update the cache files in /tmp/…/fontconfig/usr/var/cache. To verify the result look for your newly installed fonts in the output of:

/var/task/<MyLambda>/headless-chrome/fontconfig/usr/bin/fc-list

Usage with headless chrome in lambda

The fontconfig directory should now be ready to go and can be bundled along with the chromium binary. As long as all the paths are configured correctly and chromium is run with the two environmental variables (LD_LIBRARY_PATH & FONTCONFIG_PATH) set correctly it should be able to pickup the new fonts.

It's likely that including fonts will push your zipped bundle size above the 50MB limit. But there are ways around this.

@RICO1LEE
Copy link

Hey, could u plz fix this path http://anongit.freedesktop.org/git/fontconfig it is not available

The path is correct:

bash-4.2# git clone http://anongit.freedesktop.org/git/fontconfig
Cloning into 'fontconfig'...
remote: Enumerating objects: 15183, done.
remote: Counting objects: 100% (15183/15183), done.
remote: Compressing objects: 100% (7915/7915), done.
remote: Total 15183 (delta 11692), reused 9219 (delta 7242)
Receiving objects: 100% (15183/15183), 3.76 MiB | 1.53 MiB/s, done.
Resolving deltas: 100% (11692/11692), done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment