Load Font Data from Local Files in Astro
Introduction
While attempting to create paths for OGP images using satori in Astro, I encountered the following error when loading font data:
[ERROR] Unsupported OpenType signature /src
# Or, when trying to load with `fs.readFileSync`
ENOENT: no such file or directory, open '../assets/fonts/NotoSansJP-Regular.ttf'
After some research, I found that most people were fetching font data from Google Fonts over the network. However, I wanted to avoid network dependency and load local font files instead. After further investigation, I managed to implement a solution, which I will document here.
Solution
By setting up a plugin in astro.config.mjs
as shown below, it became possible to load fonts. This plugin reads font files with specified extensions (.ttf
, .woff
) as binary data and converts them into an exportable format.
export default defineConfig({
vite: {
plugins: [rawFonts([".ttf", ".woff"])],
},
});
const rawFonts = (ext) => {
return {
name: "vite-plugin-raw-fonts",
transform(_, id) {
if (ext.some((e) => id.endsWith(e))) {
const buffer = fs.readFileSync(id);
return {
code: `export default ${JSON.stringify(buffer)}`,
map: null,
};
}
},
};
}
To load and use the font data, do the following:
import React from 'react';
import satori from 'satori';
import RegularFont from "../assets/fonts/NotoSansJP-Regular.ttf";
import BoldFont from "../assets/fonts/NotoSansJP-Bold.ttf";
const generateOgpImage = async (element: React.ReactNode) => {
const svg = await satori(
element,
{
width: 1200,
height: 630,
fonts: [
{
name: "Noto Sans JP",
data: Buffer.from(RegularFont),
style: "normal",
weight: 400,
},
{
name: "Noto Sans JP",
data: Buffer.from(BoldFont),
style: "normal",
weight: 600,
},
],
}
);
// Omitted
};
Conclusion
With this setup, font data can now be loaded from local files. I plan to write another blog post later on how I generated paths for OGP images in Astro.