nuxt/fonts

Local variable Font not working

iamsebastn opened this issue · 3 comments

Loading a local variable font doesn't work. Although setting everything up correctly, it doesn't accept any weight properties

Example below:

[]
fonts: {
      assets: {
         prefix: 'public/fonts/',
      },
      families: [
         {
            name: 'Geist Sans',
            provider: 'local',
            weight: [100, 900],
            preload: true,
            display: 'swap',
            fallbacks: ['Arial', 'Helvatica'],
         },
      ],
   },

💡 weight property with values "100..900" doesn't work too

Hey @iamsebastn! 👋 I'm here to help you out with any bugs, questions, or contributions you have. Let's squash those pesky bugs together!

To resolve the issue of your local variable font not accepting any weight properties, ensure that the font file names include the weight information in a recognizable format. The code uses a weightMap and regular expressions to parse and map the weight from the font file names.

Here is the relevant part of the code that handles weight mapping and registration:

const weightMap: Record<string, string> = {
  100: 'thin',
  200: 'extra-light',
  300: 'light',
  400: 'normal',
  500: 'medium',
  600: 'semi-bold',
  700: 'bold',
  800: 'extra-bold',
  900: 'black',
}

const weights = Object.entries(weightMap).flatMap(e => e).filter(r => r !== 'normal')
const WEIGHT_RE = createRegExp(anyOf(...new Set([...weights, ...weights.map(w => w.replace('-', ''))])).groupedAs('weight').after(not.digit).before(not.digit.or(wordBoundary)), ['i'])

function generateSlugs(path: string) {
  let name = filename(path)

  const weight = name.match(WEIGHT_RE)?.groups?.weight || 'normal'
  const style = name.match(STYLE_RE)?.groups?.style || 'normal'
  const subset = name.match(SUBSET_RE)?.groups?.subset || 'latin'
  for (const slug of [weight, style, subset]) {
    name = name.replace(slug, '')
  }

  const slugs = new Set<string>()

  for (const slug of [name.replace(/\.\w*$/, ''), name.replace(/[._-]\w*$/, '')]) {
    slugs.add([
      fontFamilyToSlug(slug.replace(/[\W_]+$/, '')),
      weightMap[weight] || weight,
      style,
      subset,
    ].join('-').toLowerCase())
  }

  return [...slugs]
}

Ensure that your font file names include the weight in a format that matches the weightMap or the regular expression WEIGHT_RE. For example, if you have a font file for a bold weight, its name should include "bold" or "700" (e.g., GeistSans-Bold.ttf or GeistSans-700.ttf).

If the font file names do not include the weight information, the generateSlugs function will default to 'normal' weight, which might be why the weight properties are not being applied correctly.

Additionally, you can refer to the test cases provided in the local font provider tests to ensure that your font files are being correctly recognized and their weights are being resolved properly:

describe('local font provider', () => {
  it('should resolve correct font weights, subsets and styles', async () => {
    const cleanup = await createFixture('resolve-weights', [
      'public/MyFont.woff',
      'public/MyFont-normal.woff2',
      'public/MyFont_bold.woff2',
      'public/MyFont.700.eot',
      'public/MyFont.600-234987akd.woff2',
      'public/My-Font.200.woff2',
      'public/MyFontbold-latin.ttf',
      'public/MyFontbold-latin.woff',
    ])
    const provider = await setupFixture(['resolve-weights/public'])
    expect(provider.resolveFontFaces('MyFont', {
      fallbacks: [],
      weights: ['normal'],
      styles: ['normal'],
      subsets: ['latin'],
    })?.fonts).toMatchInlineSnapshot(`
      [
        {
          "src": [
            "/MyFont-normal.woff2",
            "/MyFont.woff",
          ],
          "style": "normal",
          "weight": "normal",
        },
      ]
    `)
    expect(provider.resolveFontFaces('MyFont', {
      fallbacks: [],
      weights: ['bold'],
      styles: ['normal'],
      subsets: ['latin'],
    })?.fonts).toMatchInlineSnapshot(`
      [
        {
          "src": [
            "/MyFont.700.eot",
            "/MyFont_bold.woff2",
            "/MyFontbold-latin.ttf",
            "/MyFontbold-latin.woff",
          ],
          "style": "normal",
          "weight": "bold",
        },
      ]
    `)
    expect(provider.resolveFontFaces('MyFont', {
      fallbacks: [],
      weights: ['extra-light'],
      styles: ['normal'],
      subsets: ['latin'],
    })?.fonts).toMatchInlineSnapshot(`
      [
        {
          "src": [
            "/My-Font.200.woff2",
          ],
          "style": "normal",
          "weight": "extra-light",
        },
      ]
    `)
    await cleanup()
  })
})

Ensure your font file names follow a similar pattern to be correctly recognized and their weights resolved [1][2].

To continue talking to Dosu, mention @dosu.

Would you be able to provide a reproduction? 🙏

More info

Why do I need to provide a reproduction?

Reproductions make it possible for us to triage and fix issues quickly with a relatively small team. It helps us discover the source of the problem, and also can reveal assumptions you or we might be making.

What will happen?

If you've provided a reproduction, we'll remove the label and try to reproduce the issue. If we can, we'll mark it as a bug and prioritise it based on its severity and how many people we think it might affect.

If needs reproduction labeled issues don't receive any substantial activity (e.g., new comments featuring a reproduction link), we'll close them. That's not because we don't care! At any point, feel free to comment with a reproduction and we'll reopen it.

How can I create a reproduction?

We have a template for starting with a minimal reproduction:

👉 https://stackblitz.com/github/nuxt/fonts/tree/main/example

A public GitHub repository is also perfect. 👌

Please ensure that the reproduction is as minimal as possible. See more details in our guide.

You might also find these other articles interesting and/or helpful:

This issue was closed because it was open for 7 days without a reproduction.