ivodolenc/nuxt-font-loader

Add Multiple google fonts

caztial opened this issue · 5 comments

Is there a way to include multiple google fronts as an array other than importing them both in a single url ?

I made the following change to add multiple urls

import { resolve } from 'path'
import pkg from '../package.json'

export default function fontLoader(moduleOptions) {
  const { nuxt, addPlugin } = this
  const options = {
    url: {
      local: undefined,
      google: undefined,
      custom: undefined
    },
    prefetch: false,
    preconnect: false,
    preload: {},
    noscript: {},
    stylesheet: true,

    ...nuxt.options.fontLoader,
    ...moduleOptions
  }

  const optionUrl = typeof options.url === 'string'

  if (
    !optionUrl &&
    !options.url.local &&
    !options.url.google &&
    !options.url.custom
  ) {
    // eslint-disable-next-line no-console
    console.warn(
      'fontLoader: You are not loading any fonts. Set a new "url" to start loading fonts. For more info, see the official docs.'
    )

    return
  }

  nuxt.hook('build:before', () => {
    if (optionUrl) {
      if (options.prefetch) {
        nuxt.options.head.link.push({
          hid: 'font-prefetch',
          rel: 'dns-prefetch',
          href: 'https://fonts.gstatic.com/',
          ...options.prefetch
        })
      }

      if (options.preconnect) {
        nuxt.options.head.link.push({
          hid: 'font-preconnect',
          rel: 'preconnect',
          href: 'https://fonts.gstatic.com/',
          crossorigin: '',
          ...options.preconnect
        })
      }

      if (options.preload) {
        nuxt.options.head.link.push({
          hid: 'font-preload',
          rel: 'preload',
          as: 'style',
          href: options.url,
          ...options.preload
        })
      }

      if (options.noscript) {
        nuxt.options.head.noscript = nuxt.options.head.noscript || []

        nuxt.options.head.noscript.push({
          hid: 'font-noscript',
          innerHTML: `<link rel="stylesheet" href="${options.url}">`,
          ...options.noscript
        })

        const hidNoscript =
          options.noscript.hid === undefined
            ? 'font-noscript'
            : options.noscript.hid

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID =
          nuxt.options.head.__dangerouslyDisableSanitizersByTagID || {}

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID[hidNoscript] = [
          'innerHTML'
        ]
      }
    }

    if (options.url.local) {
      if (options.preload.local || options.preload.local === undefined) {
        nuxt.options.head.link.push({
          hid: 'local-font-preload',
          rel: 'preload',
          as: 'style',
          href: options.url.local,
          ...options.preload.local
        })
      }

      if (options.noscript.local || options.noscript.local === undefined) {
        options.noscript.local = { ...options.noscript.local }

        nuxt.options.head.noscript = nuxt.options.head.noscript || []

        nuxt.options.head.noscript.push({
          hid: 'local-font-noscript',
          innerHTML: `<link rel="stylesheet" href="${options.url.local}">`,
          ...options.noscript.local
        })

        const hidLocalNoscript =
          options.noscript.local.hid === undefined
            ? 'local-font-noscript'
            : options.noscript.local.hid

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID =
          nuxt.options.head.__dangerouslyDisableSanitizersByTagID || {}

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID[
          hidLocalNoscript
        ] = ['innerHTML']
      }
    }

    if (options.url.google) {
      if (options.prefetch.google || options.prefetch.google === undefined) {
        nuxt.options.head.link.push({
          hid: 'google-font-prefetch',
          rel: 'dns-prefetch',
          href: 'https://fonts.gstatic.com/',
          ...options.prefetch.google
        })
      }

      if (
        options.preconnect.google ||
        options.preconnect.google === undefined
      ) {
        nuxt.options.head.link.push({
          hid: 'google-font-preconnect',
          rel: 'preconnect',
          href: 'https://fonts.gstatic.com/',
          crossorigin: '',
          ...options.preconnect.google
        })
      }

      if (options.preload.google || options.preload.google === undefined) {
        if (Array.isArray(options.url.google)) {
          options.url.google.forEach((element,c) => { 
            nuxt.options.head.link.push({
              hid: 'google-font-preload-'+c,
              rel: 'stylesheet preload prefetch',
              as: 'style',
              href: element,
              ...options.preload.google
            })
          });
        } else {
          nuxt.options.head.link.push({
            hid: 'google-font-preload',
            rel: 'preload',
            as: 'style',
            href: options.url.google,
            ...options.preload.google
          })
        }
        
      }

      if (options.noscript.google || options.noscript.google === undefined) {
        options.noscript.google = { ...options.noscript.google }

        nuxt.options.head.noscript = nuxt.options.head.noscript || []
        if (Array.isArray(options.url.google)) {
          options.url.google.forEach((element,c) => {
             nuxt.options.head.noscript.push({
              hid: 'google-font-noscript',
              innerHTML: `<link rel="stylesheet" href="${element}">`,
              ...options.noscript.google
            })
          });
        } else {
          nuxt.options.head.noscript.push({
            hid: 'google-font-noscript',
            innerHTML: `<link rel="stylesheet" href="${options.url.google}">`,
            ...options.noscript.google
          })
        }
        

        const hidGoogleNoscript =
          options.noscript.google.hid === undefined
            ? 'google-font-noscript'
            : options.noscript.google.hid

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID =
          nuxt.options.head.__dangerouslyDisableSanitizersByTagID || {}

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID[
          hidGoogleNoscript
        ] = ['innerHTML']
      }
    }

    if (options.url.custom) {
      if (options.prefetch.custom || options.prefetch.custom === undefined) {
        nuxt.options.head.link.push({
          hid: 'custom-font-prefetch',
          rel: 'dns-prefetch',
          href: 'https://use.typekit.net/',
          ...options.prefetch.custom
        })
      }

      if (
        options.preconnect.custom ||
        options.preconnect.custom === undefined
      ) {
        nuxt.options.head.link.push({
          hid: 'custom-font-preconnect',
          rel: 'preconnect',
          href: 'https://use.typekit.net/',
          crossorigin: '',
          ...options.preconnect.custom
        })
      }

      if (options.preload.custom || options.preload.custom === undefined) {
        nuxt.options.head.link.push({
          hid: 'custom-font-preload',
          rel: 'preload',
          as: 'style',
          href: options.url.custom,
          ...options.preload.custom
        })
      }

      if (options.noscript.custom || options.noscript.custom === undefined) {
        options.noscript.custom = { ...options.noscript.custom }

        nuxt.options.head.noscript = nuxt.options.head.noscript || []

        nuxt.options.head.noscript.push({
          hid: 'custom-font-noscript',
          innerHTML: `<link rel="stylesheet" href="${options.url.custom}">`,
          ...options.noscript.custom
        })

        const hidCustomNoscript =
          options.noscript.custom.hid === undefined
            ? 'custom-font-noscript'
            : options.noscript.custom.hid

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID =
          nuxt.options.head.__dangerouslyDisableSanitizersByTagID || {}

        nuxt.options.head.__dangerouslyDisableSanitizersByTagID[
          hidCustomNoscript
        ] = ['innerHTML']
      }
    }
  })

  if (options.stylesheet) {
    addPlugin({
      src: resolve(__dirname, '../templates/plugin.js'),
      fileName: 'fontLoader.js',
      ssr: false,
      options
    })
  }
}

export { pkg as meta }

Hi, thanks for your suggestion and code example.

Can you please give a real-case example or explain in more detail why this feature would be useful?

Multiple (separate) Google font sources increase the number of additional requests. To avoid this, Google offers a solution to add multiple fonts via single request.

From official Google docs:

Requesting multiple fonts allows you to use all of those fonts in your page. (But don't go overboard; most pages don't need very many fonts, and requesting a lot of fonts may make your pages slow to load.)

This article explains in more detail the best practices of loading fonts on web pages.

No problem, glad you solved it 👍