Embed next/font in external HTML / access generated asset path

75 views Asked by At

The new next/font API provides convenient calls for applying the font via className, style, or even directly as a CSS Variable. But how do I embed a reference to the font that will be included in external HTML?

In other words, if I do

// styles/font.js
import { Roboto } from 'next/font/google';

export const FontRoboto = Roboto({
  subsets: ['latin'],
  display: 'swap',
  weight: [ '700' ],
  variable: '--font-roboto'
});

What gets generated in something like

// _next/static/css/app/layout.css
/* latin-ext */
@font-face {
  font-family: '__Roboto_dc1cff';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/_next/static/media/8fb72f69fba4e3d2-s.woff2) format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

What I need to get is that font-family name, and the URL for the CSS file (actually, probably not that css file, but whichever is a minimal css file with the font declaration in it.

Use Case

What I'm actually trying to do is make sure my styling definitions are all only in one place. On the site, all is good, but under the covers, I'm using MJML's templating language to generate attractive & functional HTML emails that get sent for any number of reasons (registered as a user, submitted a contact form, etc...).

In the templates, I can use the generated Font.style.fontFamily to get the correct, full font-family expansion, but I still need to tell the template where the fonts actually are (and what they're actually called), so that the email client has the source.

In other words, a template might look like this:

const htmlOutput = mjml2html(`
  <mjml>
    <mj-head>
        <mj-attributes>
            <mj-class name="heading"
              font-family=${FontRoboto.style.fontFamily} /> // <- this works great
        </mj-attributes>
        <mj-font name="Roboto"
            href="https://fonts.googleapis.com/css?family=Roboto" /> // <- I need something like this
    </mj-head>
    // ...
    

Using the new system (i.e., where the client is not actually making any external calls to Google, and for that matter "Roboto" is no longer the actual name of the font), how to I get the necessary information to put that line correctly in the template?

NB: The MJML documentation says that href arg should "[point] to a hosted css file; that file contains a @font-face declaration."

1

There are 1 answers

1
Ahmet Firat Keler On

In NextJs 13, I can access my custom fonts over the net when I put them under the public folder.

Public Folder

So maybe this is the url you're after: https://BASE_URL/fonts/ClashGrotesk-Medium.woff

I'd also like to tell you that I put some definitions under styles/index.css file and imported it inside layout.tsx file

styles/index.css

@font-face {
  font-family: '--font-clashgrotesk';
  src: url('../public/fonts/ClashGrotesk-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: '--font-clashgrotesk';
  src: url('../public/fonts/ClashGrotesk-Medium.woff') format('woff');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

layout.tsx

import "../styles/index.css"

const clashgrotesk = localFont({
    src: [
        {
            path: "../public/fonts/ClashGrotesk-Regular.woff",
            weight: "400",
        },
        {
            path: "../public/fonts/ClashGrotesk-Medium.woff",
            weight: "500",
        }
    ],
    variable: "--font-clashgrotesk"
})

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <>
      //...
    </>
  )
}

After searching some examples, I see that they advice users to use <mj-style></mj-style> tags like below

@font-face {
    font-family: testFont;
    src: url(https://cdn2.hubspot.net/hubfs/199900/fonts/someFontFile.ttf) // maybe changing this url to the one I shared with you is the key
    format('truetype');
}